How to use Dagger 2 in an sdk? - android

I have a main application which uses Dagger (some previous version) for providing dependencies.
Now, I am writing an SDK where I am using (Dagger 2.10+). Every thing works fine, when I have an application class, as applications has (HasActivityInjector) and it's responsible for the initialization of DaggerAppComponent.
My Question is -
Should I use Dagger 2 in my sdk (I want to as it makes my code more testable)
If not, then I am considering writing my own Injection class.
If I go for it, how should I initialize at the application level as the only solution for this I found out was to have an Application class in sdk and make client extend it. (I dont want this change at client side and not a good design).
Any suggestions would be great!!

I recently had to tackle the same issue: Create an SDK that can be used in any supported Android App.
I did have to accept the premise that some of the of the Apps that would want to use the SDK won't themselves be using Dagger or even dependency injection.
The major issue with creating an SDK that uses dependency injection is, as OP has pointed out, the Application implementation in the App.
Part of the reason behind the creation of the HasActivityInjector, HasFragmentInjector or HasSupportFragmentInjector has been the need to comply with the following dependency injection rule:
A class shouldn’t know anything about how it is injected. Reference A
With the creation of the HasXInjector interfaces, Android allows the the Dagger Dependency Graph to be attached to the Application, and then for the Application to be responsible for injecting the dependencies where they need to be injected through the following code:
AndroidInjection.inject(this) // <-- 'this' being an Activity or Fragment
SDK ISSUE
The issue is that the SDK does not have an Application implementation of its own. Additionally, the SDK can not add anything to the Application implementation of the App, nor can it override the Application implementation of the App.
In the case of an external SDK, it will not even know about an Application implementation, just the Application Interface.
So even if the Application that has included the SDK uses Dagger, which is not guaranteed, the SDK will not be able to add it's Dependency Graph to the Dependency Graph used by App's Application implementation, making all SDK dependencies unreachable.
And if the Application does not use Dagger, how would the dependencies be injected in the first place?
My own solution to this issue has been to break the rule quoted above and not use the HasActivityInjector, HasFragmentInjector or HasSupportFragmentInjector for injection internally in the SDK.

Related

Why do we need to separate DI wiring from Implementation in Android multi modular architecture?

Square Inc. has presented it's internal modular architecture at Droidcon SF'19:
https://www.droidcon.com/media-detail?video=380843878
However, I'm a bit confused with some bullets. Could you please help me?
Why do they actually need :wiring modules? I find it adding complexity:
you get extra gradle module for each new feature
you have to make a sort of global injection into your Fragments somewhere in :app, because Fragments defined in :impl modules cannot access it's DaggerComponent, which is defined in :impl-wiring modules. :impl doesn't depend on :impl-wiring, because the dependency is reversed.
you cannot have an Android Dynamic Feature modules, because they should know about it's DaggerComponent in order to inject it's Fragment. But there is no way to do such injection from :app module, which is base-module for Dynamic Features.
so why :wiring modules at all?
One can merge :impl and :impl-wiring, or :fake and :fake-wiring together to eliminate all the issues mentioned above. And also, in :demo-apps one could just have a dependency on either :impl or :fake``, and not on :impl-wiring(or:fake-wiring```).
The creation of this type of modules is to separate even more. With this you generate an abstraction of the type of component you use (koin, dagger) and how. If the project is large, it makes sense to do it.
Currently I generate the following flow of dependencies between modules:
WARNING: Check the directionalities well.
:feature-A:open <- :feature-A:impl -> :feature-A:impl-wiring
:feature-A:impl-wiring -> :feature-A:impl, :feature-A:open
:app -> :feature-A:open, :feature-A:impl-wiring
I'm still not sure if app should depend on open and impl-wiring, or which app should only depend on open and open from impl-wiring.
Eventually, I came up with the following solution:
each feature consists of the following gradle-modules:
api
impl and fake
data:api
data:impl1 ... data:implN and data:fake
data:wiring
ui
demo
So, here api, impl and fake as usual, but I've my data layers separated. I bought myself that I need multiple different implementation of data layers sometimes, for example - if I develop Stock-Charts App, I could rely on Finnhub Open API or MBOUM API or provide fake implementation.
Thus I have data:api, data:implX. Indeed, data:api defines FeatureRepository interface (one or many) and data:implX provides actual implementation for them. In order to bind interface and implementation, I use data:wiring, which defines Dagger modules and component(s). In addition, I keep the same package names within each data:implX module in order to "write-once" the data:wiring module. And to replace one implementation with another, I just change a single line in data:wiring/build.gradle which states a sort of:
implementation project(":data:implA")
to
implementation project(":data:implB")
Also, to break the confusion mentioned in my original question, I introduce ui module, which contains some Views of a particular feature. Fragments go in demo (a standalone app to test feature) or in ui, they refer to viewModel which have some bindings ctor-injected from Dagger component of a feature. But the UI and library are separated here. Fragment instantiates a dedicated Dagger component that uses component dependencies to refer to feature's library bindings, such as interactor or repository etc.
So, to wrap up - separation between UI and business logic implementation (a "library") for each feature makes it possible to solve the issue. Feature's api declares an entry point to it's functionality as a library, and it's global access via Dagger multibindings from :app. So it can be used further in any :demo, :ui and :dynamic-feature.

Android Dagger 2.11 and Retrofit dynamic URLs

I’m working on a project that is based on the GithubBrowserSample demo application that’s on the Android Architecture Repo on Github.
So far, I was able to inject dependencies to my App, activities and fragments and ViewModels. Also I was able to add more Modules; right now I use two, one for Shared preference and the other a NetModule that has all the mumbo jumbo related to Retrofit/OkHttp.
But here’s the catch: currently the demos that I found that shows how to implement the Retrofit/OkHttp module has a static base URL, which doesn’t work for me since that information is available until the User provide it on the Login section…
Digging around I found that one solution is to create a Submodule (StackOverflow post) with a given Scope Instantiate the component inside my Activity/Fragment. But because I’m using Dagger 2.11 for Android to perform the injection, I have no idea how to do so…
Is there an example that I can look around, or should I give up on this path and take the OkHttp interceptor to change the URL?
Thanks in advance.

Espresso testing with Dagger 2 and custom scopes

After a recent migration to Dagger 2, the app I am working on is using an #ActivityScope for every feature. Each app feature is implemented using MVP pattern and has it's own local dagger Component setup which depends on the Application component for the dependencies that are required during the entire app lifecycle (provided by the App). Each feature’s Activity extends a base class which provides the main application component to a method that is overridden by each activity in order to set up the local dagger component (builds the local component and instantiates the local module).
The issue I am trying to solve is how to inject mocks into the Activity under test. The main problem I am experiencing is that I cannot swap the original local component and corresponding module with mocked ones at runtime. There are many articles on Espresso testing with Dagger 2 that I read, but they are not promoting clean architecture. For the most part they rely on the AppComponent to inject all Activities, where in my case, each feature’s component is responsible for injecting it’s own activity.
So far the best approach that I came up with was to introduce a component builder that is only initialised as part of the test setup and in the Activity code to go with this setup if initialised, otherwise set up the real component. However, I am reluctant to mix production and test code.
Here is a schematic which represents the Dagger setup:
Dagger 2 Setup
The approach that I took at the end was to create a custom AndroidJUnitRunner as described here and to create Components/Modules which provide mocks for each app feature, including the Application module check Google doc for best practices. Furthermore, each activity under test has to be overridden to inject the mocks (just the method that injects the mocked dependencies).
In order to keep the main app manifest clean, the overridden test activities are declared in a debug manifest.
Hope this approach helps people with a similar to my Dagger 2 setup to do their testing with Espresso and Dagger 2.
Have a rock ’n’ roll day!

Android & iOS: How to handle dependencies when building an SDK

I'm currently working on an SDK which is available on both Android & iOS platform.
For Android, we list dependencies in our Gradle file and use Maven to provide the SDK (so our dependencies are listed in the .pom file).
For iOS, we use cocoapods to handle dependendies.
The problem is the following:
* Our SDK use a dependency in version X
* One of our client might use the same dependency but in version Y
* Another client might also use the exact same dependency in version Z
So, this leads to our SDK potentially being broken on one of our client (if not both) because we ensure that it works with dependency X, but not Y and Z.
For now, the legacy code has simply imported source code of libraries causing this problem and namespaced it, such that it simulates we do not use the same library.
But in my opinion, this is not an appriopriate solution: we do not have latest fixes, it is painful to update, client has two times the library instead of one.
So, for now, I'm trying to think about a potential good solution, but couldn't find what I want on Google (maybe I'm not using the right keywords :/).
What I was thinking about was to provide support for a range of versions for each dependency. A bit like "if this method is here, execute it, otherwise, use that method of the previous version" (like selector respondTo on iOS). Then, the client should be able to use any version of the dependency at the condition it is in the supported range.
However, I don't know if it is the right way?
Is there any other solutions?
Thanks :)
For android, there are two possible solutions, a build-tool based one, and an architectural one:
1.-If you build your library with maven, you can use the "provided" scope to force your library to get the dependencies from the container running it. That way, the dependency can be provided by the app consuming your library. Note that this will not help you if the dependencies are wildly different.
2.-Abstraction to the rescue! You can subdivide your project into the main library and plugin libraries. The main library will show the user every class an method and that will be the one they will call from their apps. Inside the main library, all classes will import every external SDK or dependency in an indirect form, a generic wrapper which can be either an abstract class or an interface, and use them that way. For example, maybe you are providing an enhanced facebook login UI. Then, instead of referencing the facebook SDK directly into your View, you will reference a facebookLoginInterface and call it. Then, you'll have a secondary project, facebookLogin41, where you will implement the facebookLoginInterface using the facebook sdk 4.1, and a second one, facebookLogin418, where you implement the same interface using the facebook sdk 4.1.8. Then, implement some sort of providing logic, like a Dependency Injection framework (Roboguice providers are a very good example), maven dependency scope (provided, for example), etc, to make the library instance the facebookLoginInterface. Finally, the client just imports both the main library and the secondary project needed and uses the main library.

How to use dagger library in android library project?

I want to use dagger library to android library project. I also fallows How to use dagger in a android library project but does not get proper implementation. Anyone has demo or any Ideas about it ? I also want these library classes extends in project for some changes.
I don't know what the library is, but I would assume most of the code doesn't contain classes with uncontrolled lifecycle (activities, services, fragments, etc.).
If it is true then just use constructors to pass your dependencies.
If it is not then, you have to make a decision who is going to hold knowledge about dependencies graph. A usual solution that context is castable to objects graph knowledge, or it know how to get it. Usually, classes with uncontrolled lifecycle have access to the context

Categories

Resources