I have an abstract Activity in an Android library (AbstractActivity) that is supposed to be used in other applications as the base Activity.
Since this Activity isn't supposed to be used directly, it isn't declared in the library AndroidManifest.xml file (the real reason is because the Activity is declared as abstract) and so I can't declare it in the applications AndroidManifest.xml file.
The real problem is that when I create an application that uses the library, two .apk files get deployed to the device, Library.apk and Application.apk, and when the Application.apk is started it closes with the following message in LogCat:
ERROR/AndroidRuntime(4709): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{foo.bar/foo.bar.ApplicationActivity}: java.lang.ClassNotFoundException: foo.bar.ApplicationActivity in loader dalvik.system.PathClassLoader#44bec098
Can I reference an abstract Activity that is declared in a library and use it as the base for an Activity in a project that references this library?
Deploying separate APKs is probably not want you want. The APKs live in different sandboxes and cannot access each other.
If you want to reuse code, create an Android library project (in Eclipse, open properties of your library project, select Android and check "Is Library" under the library section.
Then, reference the library by clicking "Add" under the library section in the projects that use this library.
You end up with a single APK then.
The best (and correct) way to do this is to use the solution #Michael has suggested. However, for completeness, I thought I'd offer another solution that would work with the current setup of two apk files if for some reason you want to avoid making the one apk a library. Also note that this won't work if the activity that subclasses the AbstractActivity is loaded first, this will only work if the subclass is instantiated or called from another Activity in the same application.
In another Activity you can instantiate a PathClassLoader like so
PathClassLoader loader = new PathClassLoader("/data/data/com.yourlibrarypackage.apk", PathClassLoader.getSystemClassLoader());
And then use it to load the class you want
loader.loadClass("com.yourpackage.YourAbstractActivity")
The loadClass method returns a Class<T> object which you can ignore because it has the side-effect of making it available to other classes sharing the same memory space. That call is akin to Class.forName().
Related
My usage scenario is a bit complicated.
In the dynamic form, I only have some views and resources. Those views should have access to those resources. In my base module, I will use these views from the activity of a basic module. Both my application and activity replace the attachBaseContext method.
But when I download and install the dynamic form, my views can not access resources using the task context. However, resources are accessible from applicationContext.
I do not understand how SplitCompat works. So the classes and resources loaded by the dynamic module connect only to applicationContext?
This problem is probably caused by an Android Studio bug. Clean the project and invalidate the cache, or build the project again.
You can take a look at how Dynamic Features are implemented in this sample.
There's sample code on how to open some resources, located in a dynamic module, from the base module.
Plus, the samples includes others dynamic modules with activities in implemented in Java/Kotlin and native.
So, I'm trying to use a running application and have it access code of a not yet installed application through its .apk file. I need to access things such as the secondary applications packagename, provider, bundles, data, etc all without installing it onto the phone.
So far from what I understand I can use either one of two things.
1) dexClassLoader. With this option I need to be able to access the .apk file from some sort of storage such as an SD card.
2) pathClassLoader. Seems like the correct option here. Can use JAR/ZIP/APK files with this option.
Essentially I'm trying to load the second application into the first one by binding its code to a running process, I'm just having trouble accessing its code without decompiling it. I guess my question is should I be using/trying the first or second option here, or is a third option available?
While you can dynamically load code from the second application using dexClassLoader, etc., you cannot dynamically add new components to your application. Any component must be statically declared in the AndroidManifest.xml.
So you cannot, for example, "import" an activity from the second apk into your main application. You can access the class for that Activity, but you can't directly start an activity using it.
Depending on your requirements, it might be possible to create a "placeholder" activity in your main application, which creates an instance of the Activity class from the secondary apk and forwards all method calls to that instance. In general, I would not actually suggest this. I suspect it would be very difficult (if not impossible in some cases) to actually do correctly.
I read this answer and undestood why I should keep names of my services, activities, and custom views. But should I keep my classes which derive from android.support.v4.app.Fragment?
I also took a look at the defualt Proguard config file %SDK_DIR%\sdk\tools\proguard\proguard-android.txt, and there were no rules regarding fragments.
The main reason why you would need to keep a class, is because it is accessed via reflection.
Fragments are normally not accessed via reflection, so you don't have to keep them.
Except if you reference them directly in layout files (because parsing layout files uses reflection).
As others have already pointed out, the main reason to keep UI elements like Fragments from being obfuscated is because they are referenced from other resources that are not processed by ProGuard, e.g. layout files.
If you would be using DexGuard you could also obfuscate Fragments and other UI classes as DexGuard will process all application resources together, allowing it to modify class names whereever they are used (except when used via reflection of course).
I'm having a lot of doubts and after two days of searching I still haven't found a good answer for my problem.
I have an app's project that is already in the store and this project have lots of Activities, Fragments, Services, IntentServices, Layouts, and resources (images, strings, integers, colors, styles, raws, drawables, etc...).
Now, I need to implement a new app that is almost a copy of the first one where I need only to change the background, some resources (but almost 99% stay the same), and maybe in one or two fragments I'll need to change some code (implement different logic statements).
I decided and I think it's natural to convert the all project in an library project.
I did:
1º Create a new project called framework and configured as library. Copied all code and resources (with the exception of assets folder) from the original project to here.
2º In the original project I leave only the manifest, proguard file. I change the manifest and proguard file to reference the classes of the new library.
I tested the app to see if was still working and it was Ok. Until now I did only the separation.
Now, came the problem. I need to create a solution reusable,and scalar for the library that allows me to use it in different apps.
In my original project I created a subclass of Application class that I use for global variables.
Without any others ideas, I decided the following:
1º Convert my MyApplication class in an abstract class. Also, I create an interface ApplicationInterface with some methods like isBackgroundOverlayed() or getBackgroundResource() that I use in the fragments to change the backgrounds or any other logic from the originally defined.
2º In the App's project, I created a new Application class that extends the abstract class MyApplication and implements the interface ApplicationInterface and which is declared in the Application tag in the manifest file.
Conclusion: This all works and I was able to have two app's projects with different background and other images like logos and even change some code logic. An example is in the original App when the user press one certain button, the App shows a dialog choice. In the new app when the user press the button it execute one fragment (without choice).
My concerns: I don't feel this is the best solution for the problem or best practice or good "pattern".
Do you have any ideas?
Thank you in advance!
ps: Sorry if I haven't use this forum properly. I search for an answer but I didn't found any.
I think you have achieved what you wanted, but that was a lengthy and time consuming process. One more thing I would like to mention is you should not change library projects for different applications
As said on Android developers guide :
Library projects contain shareable Android source code and resources that you can reference in Android projects. This is useful when you have common code that you want to reuse.
you can read more from here
Also you have to figure out,which lib is doing which work in case you forget what changes you have made
I would suggest you to keep a separate copy of original project and then import it into new work space in Eclipse (by checking copy project into current work space so that you have a new copy of your project) and consider changing its package name to get a new project
you can refer ans on this link to see how to change package name`
I have been happily refactoring code from different versions of the same app (paid/free) into Android library projects so that the actual apps can simply customize the library and reduce code duplication.
One thing I'm started to wonder is what getApplicationContext() inside the library code means? Is is the same ApplicationContext as one would get from the child apps? What happens when I access SharedPreferences from a library project's getApplicationContext() instead of the original app's getApplicationContext()? Will the SharedPreferences file be same or different?
What if I had used the activity to access SharedPreferences? Does it matter that the activity is now a library activity and not the original app? Is the SharedPreferences the same?
Thanks for clarifying.
When the APK is packaged up then all classes will be belong to the main application.
call getApplicationContext().getPackageName() and it will return the app's package name, and not the library's package.
I have the same setup for a free/paid application and no issues when I moved my classes into a library project.
However you have to check your xml files (manifest, widgets, etc.) to use the full package name of your library project.
A library project is almost like having all the code in one project. There are a couple of things to watch out for related to namespaces but generally it works very well.
e.g. Your library has its own namespace
Library package name = uk.co.lib
Main App package name = uk.co.app
Activities in the library that you want tro access from the main app have to be added to the app manifest. Activity named A in library project would be added to manifest in main app like this:
<activity android:name="uk.co.lib.A">
Accessing shared preferences etc would give the same result from either namespace and would return the preferences for the app.
There is only one application so there is only one ApplicationContext