so I have a couple of features that share common code - let's call them "feature1" and "feature2". I can't add the shared code as dependencies for "feature1" and "feature2" - Android studio throws the following error:
Multiple APKs packaging the same library can cause runtime errors.
Adding the above library as a dependency of the base module will resolve this
issue by packaging the library with the base APK instead.
So I thought I just create another dynamic feature module - let's call it "core" - to deliver the shared dependencies there. Which also works, kind of. I can access all the java classes from "core" inside "feature1" and "feature2", but as soon as I want to access a resource I get an ResourceNotFoundException. The features are deliver Fragments that call SplitCompat.install(context) in their onAttach() function.
So my question is - is it even possible to have a dynamic feature module where common code is stored, or should this all go in the app?
Thanks & Regards, Romanski
Now support for feature on feature dependencies have been introduced in the latest release of gradle:
https://developer.android.com/studio/releases/gradle-plugin#feature-on-feature
Related
I want to generate a fat-aar of an app module and use it as a dependency in another app.
I have used this library to generate the fat-aar.
I have an app module which is converted as a library module and a feature module called splash and Splash module is included in the app module.
With the help of above library I have successfully generated the fat-aar, but this fat-aar doesnot include the drawable resources of Splash module which crashes the app at run time with below exception.
java.lang.NoSuchFieldError: No static field ic_app_splash of type I in class
Lcom/app/passenger/R$drawable; or its superclasses
This ic_app_splash is present inside the splash module.
Please provide the solution as why the fat-aar is not including the resources of a module.
I suppose that is Issue 406. Reading the associated issues your problem might be solved with the answer to Issue 19 and the corresponding explanation by the lib's dev which, in short, is:
The support lib version that your application uses is best to be the same as the library uses.
Note, that the developer also states:
I am no longer engaged in research and development, so the project will not be updated and maintained.
However you can also use the probably more common way, and either create AARs with Android Studio or via CLI with AAPT.
I'm building an Android Library and I would like some of its features to be downloaded only on-demand, as dynamic feature modules.
Is it possible to use Dynamic Delivery (from Google Play Core library) in an Android Library project?
I tried adding dynamicFeatures = [':my_dynamic_feature'] to my Library project's build.gradle, but when I try to do a Gradle sync, I'm getting the following error:
Could not set unknown property 'dynamicFeatures' for object of type com.android.build.gradle.LibraryExtension.
For this reason I suspect that Dynamic Delivery is only supported for 'com.android.application' but not for 'com.android.library'.
Can someone confirm whether this is supported or not?
Or at least planned for a future release of Play Core library?
Thanks!
Yes, currently it can only be used from the application class.
If you want to design your library in a way that it can later support a dynamic feature, you can move the dynamic feature related code to a separate library, let's call it DFLibrary.
Instead of directly calling the DFLibrary methods, you can use reflection.
Now, any client that wants to use your library and the DFLibrary but does not want to handle dynamic feature installation can include the dependencies of both your library and DFLibrary.
In case the client wants to use DFLibrary as a dynamic feature module, it can itself create a Dynamic feature module and include the DFLibrary dependency in it and then handle the downloading of that dynamic feature module.
I am looking into a way of creating a dependency library structure for my current project, where I create a core library dependency then use addition dependencies to add functionality automatically, however, I am aiming for a solution where my additional dependencies to not require in the inclusion of the Core library. Class objects within the additional dependencies with have access and use code that is located within the Core library (for example, an abstract class or interface).
I have seen an example of this with Ironsource, an advertising platform, if the developer wanted to, for example, add facebook adverts to their project, they would need to add the following dependencies in Gradle.
implementation 'com.ironsource.sdk:mediationsdk:6.9.1#jar'
implementation 'com.ironsource.adapters:facebookadapter:4.3.4#jar'
However, if they remove the main mediation SDK, the facebookadapter SDK no longer works as it is missing a class it is using within the mediation SDK. but instead returns an Unresolved Superclass error, as the superclass is only found in the mediationsdk dependancy.
My question is how did they do this? How did they use code in the facebookadapter(additional) that is only available in the mediationsdk(Core) library? and how can I replicate this dependancy style?
I have tried having both my core and additional libraries have the same package information but to no avail.
As far as I got your question correctly, you are interested in how Library B can use a class that shipped by Library A without including that explicitly. That is basically a difference between implementation and api in gradle dependencies specification, the first one does not include the dependencies transitively into your build. So when you develop Library B, and have Library A attached as implementation, it's not gonna be included into build artifacts, so consumer should provide it explicitly.
A common example of this approach is Retrofit or OkHttp, many 3rd party SDKs use them internally, but they don't want to ship them as built-in dependencies, so they do ask consumers to provide them.
So most likely, they just use implementation to locally resolve the ABI, but don't ship it inside of each com.ironsource.adapters:* module because it will be shipped many times then.
More information about different compile options:
https://developer.android.com/studio/build/dependencies#dependency_configurations
I'm in the process of writing an instant app for others to learn how to write an instant app and hoping to get some ideas on how to best structure the app for dependencies.
Now reading the Android developer docs on project structure and referencing the diagram below:
I'm wondering with the new gradle 3.0 dependency configurations, what libraries should live in which modules?
Base Feature
I was thinking pretty much anything in the base feature module should be using the api gradle configuration since the base feature module essentially compiles down to an AAR library file. One question I might have for this module, if one was to use ROOM would this be the module to place it in?
Feature
Now in the feature modules, it is my understanding that everything should be utilizing the implementation gradle configuration since these modules should not leak there dependencies out to any other modules in order to truly make them independent from one another.
Just looking for some confirmation of my understanding and also any ideas to help with the project. Here is the github repo if you want to check out the code I got so far. It is really simple at the moment, but I was thinking about messing around with the Star Wars API using Retrofit.
Thanks for any help and gladly accept any contributions if you want to to try and make a pull request yourself for any other concepts in making an instant app that others should know.
Shared details in your question are correct. Consider some of the below suggestions which add to the points mentioned by TWL:
Adding certain libraries to specific feature module which should
be included in the feature module only, instead of being added in the
base APK.
For example, let's say you have an application that depends on
libraries X, Y, and Z. Initially, you may pack all the libraries in
the base module by placing all the dependencies in the base
gradle.build file. But if only the code in the feature module requires
library Z, it makes sense to move that dependency from the base module
to the feature module.This works as long as no other feature modules
depend on the same library. If multiple feature modules use the same
library it definitely makes sense to keep it in the base module.
Taking care of Transitive dependencies.
Transitive dependencies occur when the library your project relies
upon depends on another library, which in turn may depend on yet
another library. Sometimes those transitive dependencies may contain
unexpected surprises such as libraries you do not need at all (i.e. a
JSON processing library you never use in your code.)
I hope this adds some information to your query,
I'm wondering with the new gradle 3.0 dependency configurations, what libraries should live in which modules?
Some of these links can also be referred for additional data:
Android Instant Apps(best-practices)
AIA structure
As mentioned by keyboardsurfer, your dependency assumption is in the right direction.
Base is at the root and acts like a library shared by all the
non-base feature modules, so its shared dependencies should be set with
api so that modules that depend on it can also access them. (though, base doesn't have to act only like a library, it can
also be a feature APK itself)
Features, as an instant app, each one extends out to the end as its own APK, so there's no reason it should be leaking its dependencies to any other modules and therefore dependencies should be set with implementation here.
Within the Google Samples, the cookie-api and install-api are some samples that more clearly demonstrate the dependency configuration usage as how I explained above.
I am making an Android app with Wear capabilities.
I want to share some code between the wearable and handheld modules. Specifically, I want to share communication code that uses Google Play Services classes, e.g. com.google.android.gms.common.api.GoogleApiClient.
The obvious way to do this is to have a module (I called it common) and add a dependency to it in both the handheld and the wearable modules.
Since this common module uses Play Services, I need to make it depend on com.google.android.gms:play-services.
I was not sure what to put for the version number - the official documentation here says to use 5.0.77, but that does not work, as the latest SDK does not have this version anywhere, instead it comes with 5.0.89 and 5.2.08.
If I use 5.0.89, the Wearable app does not work, with this error: Google Play services out of date. Requires 5089000 but found 5077534. The version on the watch is older than the one I used to compile.
Instead of depending on com.google.android.gms:play-services the common module could depend on com.google.android.gms:play-services-wearable but then there is a conflict when building because the handheld module depends on com.google.android.gms:play-services, and these two artefacts use the same package name (com.google.android.gms), and so the gradle build fails.
What's the solution?
.
EDIT after discussing a bit and to make my question clearer.
To be able to use communication APIs in my common module I have two choices:
Make common depend on com.google.android.gms:play-services
Make common depend on com.google.android.gms:play-services-wear
⇒ Solution 1 does not work because the version available (5.0.89) for development is more recent than the one on the watch (5.0.77).
⇒ Solution 2 does not work because the handheld module already depends on com.google.android.gms:play-services, which conflicts with com.google.android.gms:play-services-wear.
I bumped into the same problem a few days ago. My shared module depended on com.google.android.gms:play-services as well, so Gradle refused to build and kept nagging at me:
Error: more than one library with package name 'com.google.android.gms
I added this line to my mobile project's gradle file and the error disappeared magically:
compile(project(':sharedModule')) {
transitive = false
}
Take a look here: https://github.com/tajchert/SWear_Weather
I had created common project that is shared between mobile and wear, and contains my constants. Remember to set there dummy manifest file and:
apply plugin: 'com.android.library' in build.gradle file.
I had also encountered problem with play-services version - I had solved it by using
compile 'com.google.android.gms:play-services-wearable:+'
compile 'com.google.android.support:wearable:+'
instead of specifying particular version - to be honest it should be separete question - as it is out of scope of previous (sharing code between projects).
It is possible to need invalidate cache/restart after changing - you can/should remove build paths in your projects to get rid of all other versions.