0

I have a 3rd party library that exposes its functionality through a listener interface. The requirement of the library is that it gets initialized in the onCreate of the custom Android Application class.

public class CustomApplicationWithListener extends Application implements ThirdPartyListener {
   public void onCreate() {
     if(feature.isTurnedOn()){
       // the library requires an application instance of type ThirdPartyListener
       init(this);
     }
   }
}

I was trying to hide this functionality behind a feature flag and was wondering if there is a way to abstract the listener from the application class and only define it when the feature is needed. Only then we declare that interface. I know the custom application class needs to be defined in the manifest. Is there a way to dynamically decide at runtime that if the feature is enabled then initialize the base custom application object with the third party listener something like below and let the main manifest know the version we are going to use?

var application: Application?
if(feature.isTurnedOn()){
 application = CustomApplicationWithListener()
} else {
 application = CustomApplication
}
luckysing_noobster
  • 1,933
  • 5
  • 24
  • 50
  • What exactly do you want to achieve? Is your goal switching this in runtime or rather having two versions of your app using single codebase? – mlc Apr 21 '20 at 22:11
  • 1
    On Android 9.0 and higher, you could use `AppComponentFactory` to create a custom instance of your `Application`. However, since the rest of your app is not set up, you will not know what the feature flag value is. Why are you having your `Application` class implement this interface, instead of having that be implemented on some other object? – CommonsWare Apr 21 '20 at 22:15
  • If I implement the interface in some other class I get a runtime exception saying the library needs to be initialized in the application oncreate and expects an application instance of listener type! By feature flag here I am reading the flag on the client I am not hitting any end points to decide whether I want to shwo that specific feature. Its a compile time flag – luckysing_noobster Apr 21 '20 at 22:54
  • @CommonsWare Do version prior to Android 9.0 have the support for `AppComponentFactory ` – luckysing_noobster Apr 21 '20 at 22:55
  • @luckysing_noobster: No, sorry. – CommonsWare Apr 21 '20 at 22:58

1 Answers1

1

Code generation to be done in android application at runtime is not an easy task and would be done with Reflection. Take a look at Java's Reflection API to understand how reflection works.

On the other hand, compiler time codegen is rather not that hard an can be achieved by Annotation Processors. Refer to this blogpost to understand how annotation processors work.

Take a look at Dynamic Modules which allow users to download specific features on demand. This may be the most adept solution to your case. Setting up a PreferenceFragment having feature flag views and reading the value through SharedPreferences in a solution.

I still question why you do not want to declare the 3rd party library in your class application. A lot of 3rd party libraries often required instantiation in the base application class. If library dependency is your answer, then that can be solved by splitting up own application into presentation, data and domain module. This will at least isolate the android framework from your business logic.

Karan Dhillon
  • 1,186
  • 1
  • 6
  • 14
  • You might want to edit your answer to explain what this has to do with how feature flags might control `Application` instantiation. – CommonsWare Apr 21 '20 at 22:14
  • @CommonsWare Well feature flags would not help as application instantiation will take place before the PreferenceFragment gets generated. So the application onCreate will already have been executed. However, reinitializing the application by using sharedPreferences might solve this problem. In that case, OP can refer to this comment if he's interested. – Karan Dhillon Apr 21 '20 at 22:17
  • "application instantiation will take place before the PreferenceFragment gets generated" -- note that the question does not refer to a `PreferenceFragment`. "reinitializing the application by using sharedPreferences might solve this problem" -- note that neither the question, nor your answer, refer to `SharedPreferences`. – CommonsWare Apr 21 '20 at 22:25
  • 1
    @CommonsWare `PreferenceFragment` was used simply to refer wherever the feature flag views are being inflated. As the most logical place to do so would be a `PreferenceFragment`, hence there was such mention. Also, reinstating the application is not a good user experience, hence it was not included in the answer to not promote it, and the reason why it was mentioned in the comment, for those who are curious. – Karan Dhillon Apr 21 '20 at 22:35
  • "wherever the feature flag views are being inflated" -- ah, OK. You are assuming that feature flags are controlled by some in-app UI, such as a debug panel. I am assuming that the feature flags are delivered by a server, as that is how I hear the term "feature flag" get used the most. The question does not really state one way or another. If you could make some edits to your answer -- such as explaining how what you have written ties into feature flags -- I can retract my downvote. I cannot retract it until you edit the answer in some form, anyway. – CommonsWare Apr 21 '20 at 22:45
  • 2
    @CommonsWare Made it more explicit in the answer how feature flag views might solve the problem. Also, delivering feature-flags through server might not be a good idea as that will need apk to contain unnecessary assets which will remain unused and increase the apk size. It is always a good idea if following dynamic feature module approach to go for a certain inital set of "must" features and then let android app bundle to deliver them whenever it is required. – Karan Dhillon Apr 21 '20 at 22:50