Pluginization Framework of VirtualAPK
In order to reduce the difficulty of reading, this article does not use the word “plug-in”, but uses easy-to-understand “module” to explain. This article elaborates from the following 6 aspects. If there is something wrong with understanding, I hope that you will be enlightened.
- What is VirtualAPK
- VirtualAPK usage scenarios
- How to use VirtualAPK
- Brief Analysis of VirtualAPK Principle
- VirtualAPK download and identification
- VirtualAPK loading and application
What is VirtualAPK
VirtualAPK is an excellent plug-in framework developed by Didi Chuxing.
VirtualAPK usage scenarios
- When the project is huge and you want to implement multiple APKs, but do not want to occupy too much memory-complexity, memory
We know that when Android opens an APK application, it creates a process and runs in a separate virtual machine. Creating a process consumes relatively large memory. If you create multiple processes, it will occupy more memory. But we also want to divide the project into multiple APKs and develop them in parallel, and then multiple APKs can communicate with each other. In response to such a demand pain point, VirtualAPK can be satisfied, because it is embedded into the project by using APK as a plug-in without creating a new process.
- When the project needs decoupling-decoupling
For example, a project is divided into a host and multiple modules. We hope that each module and host are decoupled as much as possible. VirtualAPK is a way of independent APK, which can be satisfied.
- Each module in the project can communicate with the host or communicate with each other-communication
The host and each module are implemented by referring to the same aar, that is, aar is used as a three-way relay to communicate with each other, and this module is automatically removed from the APK when the module is built.
- The modules in the project can be self-upgraded-changeable
Each module may frequently update functions or fix bugs. If we also use an Apk to access all module requirements, then changes in each module require Apk to update, so we hope that each module can be upgraded automatically. When VirtualAPK loads the APK, it goes to an absolute path. We only need to change the APK file under this absolute path to achieve the module self-upgrade.
How to use VirtualAPK
Follow the 12 steps below to easily access VirtualAPK, first list the whole, and then expand step by step:
- Add classpath ‘com.didi.virtualapk: gradle: 0.9.8.6’ to the build.gradle file in the host project’s root directory
- In the host project, add apply plugin: ‘com.didi.virtualapk.host’ to the top of the build.gradle file under the app
- Add compile ‘com.didi.virtualapk: core: 0.9.8’ to the bottom of the build.gradle file under the host project
- Add PluginManager.getInstance (base) .init () to the attachBaseContext () method under the host project and Application;
- Add obfuscation rules to the proguard-rules.pro file under the host project and app
- Add classpath ‘com.didi.virtualapk: gradle: 0.9.8.6’ to the build.gradle file in the module APK and root directory
- Add apply plugin: ‘com.didi.virtualapk.plugin’ to the top of the build.gradle file under the module APK and app
- Configure VirtualAPK at the bottom of the module APK, app. Build.gradle file
- Load the module APK in the host project and the file under the app, and then you can jump to the module APK or communicate with it
- Add read and write storage permissions to the AndroidManifest.xml file under the host project and app
- Build Host Project and Module APK
- Copy the module APK to a directory on the storage device, and install and run the host APK
(1) Add the classpath ‘com.didi.virtualapk: gradle: 0.9.8.6’ to the build.gradle file in the root directory of the host project.
dependencies {
//noinspection GradleDependency
classpath ‘com.android.tools.build:gradle:3.1.3’
classpath group: ‘org.tmatesoft.svnkit’, name: ‘svnkit’, version: ‘1.8.11’
classpath ‘com.didi.virtualapk:gradle:0.9.8.6’
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
(2) In the host project, add the apply plugin: ‘com.didi.virtualapk.host’ to the top of the build.gradle file under the app
apply plugin: ‘com.android.application’
apply plugin: ‘com.didi.virtualapk.host’
(3) Add compile ‘com.didi.virtualapk: core: 0.9.8’ to the bottom of the build.gradle file in the host project and app
dependencies {
implementation fileTree(dir: ‘libs’, include: [‘*.jar’])
testImplementation ‘junit:junit:4.12’
androidTestImplementation ‘com.android.support.test:runner:1.0.2’
androidTestImplementation ‘com.android.support.test.espresso:espresso-core:3.0.2’
implementation ‘com.android.support:recyclerview-v7:27.1.1’
implementation ‘com.android.support:appcompat-v7:27.1.1’
implementation(name: ‘wifidiagnose-release’, ext: ‘aar’)
implementation ‘com.didi.virtualapk:core:0.9.8’
}
(4) Add PluginManager.getInstance (base) .init () to the attachBaseContext () method under the host project and Application;
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
PluginManager.getInstance(base).init();
}
(5) Add obfuscation rules to the proguard-rules.pro file under the host project and app
-keep class com.didi.virtualapk.internal.VAInstrumentation { *; }-keep class com.didi.virtualapk.internal.PluginContentResolver { *; }-dontwarn com.didi.virtualapk.**-dontwarn android.**-keep class android.** { *; }
(6) Add classpath ‘com.didi.virtualapk: gradle: 0.9.8.6’ to the build.gradle file in the module APK and root
dependencies {
classpath ‘com.android.tools.build:gradle:3.1.2’
// classpath (‘com.tencent.tinker:tinker-patch-gradle-plugin:1.9.1’)
// classpath (“com.tinkerpatch.sdk:tinkerpatch-gradle-plugin:${TINKERPATCH_VERSION}”) { changing = true }
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath ‘com.didi.virtualapk:gradle:0.9.8.6’
}
(7) Add apply plugin: ‘com.didi.virtualapk.plugin’ to the top of the build.gradle file under the module APK and app
apply plugin: ‘com.android.application’
//apply from: ‘tinkerpatch.gradle’
apply plugin: ‘com.didi.virtualapk.plugin’
(8) Configure VirtualAPK at the bottom of the build.gradle file under the module APK and app
virtualApk {
// packageId in the plugin resource table, you need to ensure that different plugins have different packageIds.
// range 0x1f-0x7f
packageId = 0x6f
// path of the host project application module, the plug-in needs to rely on this path
targetHost = ‘C: \\ AndroidStudioProjects \\ SystemDiagnose \\ app ‘
// The default is true. If the plugin has a class that references the host, then this option can make the plugin and the host remain confused and consistent.
ApplyHostMapping = true
}
(9) Load the module APK in the host project and the file under the app, and then you can jump to the module APK or communicate with it
public class TestActivity extends Activity {
private static final String TAG = TestActivity.class.getSimpleName();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG,”onCreate()”);
String pluginPath = Environment.getExternalStorageDirectory().getAbsolutePath().concat(“/plugin.apk”);
File plugin = new File(pluginPath);
try {
PluginManager.getInstance(getApplicationContext()).loadPlugin(plugin);
} catch (Exception e) {
Log.e(TAG,”error”);
e.printStackTrace();
}
findViewById(R.id.iv_get_plugin).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG,”onCLick”);
// Given “com.agg.application” is the package name of plugin APK,
// and there is an activity called `MainActivity`.
Intent intent = new Intent();
intent.setClassName(“com.agg.application”, “com.agg.application.view.activity.MainActivity”);
startActivity(intent);
}
});
}
}
(10) Add read and write storage permissions to the AndroidManifest.xml file under the host project and app
<uses-permission android:name=”android.permission.READ_EXTERNAL_STORAGE” />
<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE” />
(11) Build host project and module APK
The construction of the host is the same as the normal apk. You can use the Build> Generate Signed APK method or the command: gradlew clean assembleRelease, or as shown below, the completed apk is in app> build> outputs> apk> release Under contents.
The module APK build command can be: gradlew clean assemblePlugin, or as shown below, the completed apk is under the app> build> outputs> plugin> release directory.
(12) Copy the module APK to a directory on the storage device, and install and run the host APK
The storage device directory is used in step 9. At this point, access to VirtualAPK is complete.
Remarks:
- TargetHost configuration problem-targetHost can set an absolute path or a relative path, which is the path of the application module of the host project. The construction of the module APK depends on this path.
- Read and write storage permission settings-mobile phones above 6.0 need to dynamically apply or manually open permissions in the settings.
Brief Analysis of VirtualAPK Principle
Fundamental
- ClassLoader that merges the host and the plug-in needs to be aware that the classes in the plug-in cannot be duplicated with the host
- Merge plugin and host resourcesReset packageId for plugin resources, merge plugin resources and host resources
- Remove the reference to the host from the plug-in package . When building, remove the reference to the host’s code and resources through the Gradle plugin.
Implementation principle of the four major components
- Activity uses the pit in the host manifest to bypass the system check, and then load the real activity;
- Service dynamically proxy AMS, intercept service related requests, transfer them to be Service Runtimeprocessed, and Service Runtimewill take over all operations of the system;
- Receiver re-registers the statically registered receiver in the plugin;
- ContentProvider dynamically proxies IContentProvider, intercepts provider-related requests, transfers them to Provider Runtimeprocessing, Provider Runtimeand takes over all operations of the system.
Overall architecture diagram
Application architecture diagram
VirtualAPK download and identification
VirtualAPK loading and application
First, use the sequence diagram to extract the process of the VirtualAPK source code. Due to my limited energy, I will not paste the specific code, and I will add it when I have time.
Reference document
Problems that may occur when accessing VirtualAPK and their solutions
Hongyang version of VirtualAPK source code analysis
VirtualAPK source code analysis resource loading
Article last published at: 2019-11-23 20:40:08
Orignal link:https://blog.csdn.net/Agg_bin/article/details/103210946