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.

  1. What is VirtualAPK
  2. VirtualAPK usage scenarios
  3. How to use VirtualAPK
  4. Brief Analysis of VirtualAPK Principle
  5. VirtualAPK download and identification
  6. 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:

  1. Add classpath ‘com.didi.virtualapk: gradle: 0.9.8.6’ to the build.gradle file in the host project’s root directory
  2. In the host project, add apply plugin: ‘com.didi.virtualapk.host’ to the top of the build.gradle file under the app
  3. Add compile ‘com.didi.virtualapk: core: 0.9.8’ to the bottom of the build.gradle file under the host project
  4. Add PluginManager.getInstance (base) .init () to the attachBaseContext () method under the host project and Application;
  5. Add obfuscation rules to the proguard-rules.pro file under the host project and app
  6. Add classpath ‘com.didi.virtualapk: gradle: 0.9.8.6’ to the build.gradle file in the module APK and root directory
  7. Add apply plugin: ‘com.didi.virtualapk.plugin’ to the top of the build.gradle file under the module APK and app
  8. Configure VirtualAPK at the bottom of the module APK, app. Build.gradle file
  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
  10. Add read and write storage permissions to the AndroidManifest.xml file under the host project and app
  11. Build Host Project and Module APK
  12. 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.

Pluginization_Framework_of_VirtualAPK_0.png

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.

Pluginization_Framework_of_VirtualAPK_1.png

(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

Pluginization_Framework_of_VirtualAPK_2.png

Application architecture diagram

Pluginization_Framework_of_VirtualAPK_3.png

 

VirtualAPK download and identification

Pluginization_Framework_of_VirtualAPK_4.png

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.

Pluginization_Framework_of_VirtualAPK_5.png

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