This topic describes how to integrate the Mobile Hotfix software development kit (SDK).
Prerequisites
To download the SDK, see "Download the SDK" in EMAS Quick Start.
A demo program is available at this GitHub address.
Limits
Supports Android 4.3 and later. If you use self-developed devices and systems, you must disable system-level JIT before integration.
You must use ProGuard for code obfuscation.
The hotpatching SDK supports fixes for only Java code, resource files, and .so files.
Integration steps
Add project dependencies
Android Studio integration method
Use a Gradle remote repository dependency. Open the project, find your app's `build.gradle` file, and add the following configurations:
Add the Maven repository address:
repositories { maven { url "http://maven.aliyun.com/nexus/content/repositories/releases" } }Add the Gradle coordinate version dependency:
android { ...... defaultConfig { applicationId "com.xxx.xxx" // Package name ...... ndk { // Select the .so libraries for the corresponding CPU types. // Hotpatching supports five types. abiFilters 'arm64-v8a', 'armeabi', 'armeabi-v7a', 'x86', 'x86_64' } ...... } ...... } dependencies { ...... compile 'com.aliyun.ams:alicloud-android-hotfix:3.4.2' ...... }If you cannot access the repository, you can use local dependencies.
ImportantWhen you use Android Studio to package and generate an APK, you must disable Instant Run.
If you use a Gradle plugin version later than 4.2, resource optimization may be automatically enabled. This can obfuscate resource names and cause the patch generation process to stop responding at the "Start building patch..." step and fail to parse the APK package. To resolve this issue, add `android.enableResourceOptimizations=false` to `gradle.properties`. Then, regenerate the baseline package and the fix package before you generate the patch.
If you enable code obfuscation, you must disable R8 to prevent the generated patch from being too large. To do this, add `android.enableR8=false` to `gradle.properties`. Then, regenerate the baseline package and the fix package before you generate the patch.
If a UTDID conflict occurs during SDK integration, see Alibaba Cloud SDK UTDID Conflict Solution.
Eclipse integration method
Download OneSDK.zip. Unzip the file and open the `libs` folder. You must add dependencies for all .aar and .jar files in the `libs` folder.
To add dependencies for .aar files, unzip the .aar file. Copy the .so files from the `jni` folder to your project's `jni` folder. In Eclipse, the `jni` folder is typically the `libs` folder. Copy the .jar file to the project's `libs` folder. Merge the content of the `AndroidManifest.xml` file into your project's `AndroidManifest.xml` file.
Copy all .jar files to the project's `libs` folder.
ImportantIf a duplicate UTDID class exception occurs during compilation, see Alibaba Cloud SDK UTDID Conflict Solution.
Add application permissions
The Sophix SDK uses the following permissions. If you use Maven or .aar dependencies, you do not need to configure them manually. The configurations are specified in `AndroidManifest.xml`.
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>SDK permission
Required
Description
INTERNET
Yes
Allows network requests. Used to download patches.
ACCESS_NETWORK_STATE
Yes
Gets carrier and network type information. Used to collect statistics on patch loading status across different networks.
ACCESS_WIFI_STATE
Yes
Gets carrier and network type information. Used to collect statistics on patch loading status across different networks.
READ_EXTERNAL_STORAGE
No
Read permission for external storage. Required by the debugging tool to load local patches from an SD card.
NoteThe
READ_EXTERNAL_STORAGEpermission is a Dangerous Permission. It is required only for the debugging tool to retrieve external patches and does not affect the loading of patches published online. When debugging, handle runtime permission requests for Android 6.0 and later as needed.Configure the AndroidManifest.xml file
In the
AndroidManifest.xmlfile, add the following configurations under theapplicationnode:<meta-data android:name="com.taobao.android.hotfix.IDSECRET" android:value="App ID" /> <meta-data android:name="com.taobao.android.hotfix.APPSECRET" android:value="App Secret" /> <meta-data android:name="com.taobao.android.hotfix.RSASECRET" android:value="RSA key" />Replace the `value` placeholders with the App ID, App Secret, and RSA key that you can obtain from the Mobile Hotfix service on the platform. For more information about how to obtain the App Secret and RSA key, see View application information. For security, we recommend that you use the `setSecretMetaData` method to set these values. For more information, see the method description in SDK API. If you cannot find the corresponding parameters, see "Download the SDK" in EMAS Quick Start to obtain the application configuration information.
NoteIn addition, hotpatching does not currently support reading JSON files from the unified EMAS plugin.
IDSECRET, APPSECRET, and RSASECRETwill be used for billing. Store them securely.To avoid leaking the
IDSECRET, APPSECRET, RSASECRETparameters or data generated during app runtime in logs, we recommend that you disable SDK debug logs in the production version.Because you must set the
IDSECRET, APPSECRET, and RSASECRETparameters in your code, we recommend that you enable obfuscation before you publish your application. This helps prevent information leaks from malicious decompilation.
Obfuscation configuration
# Used for the baseline package to generate mapping.txt -printmapping mapping.txt # The generated mapping.txt is in the app/build/outputs/mapping/release path. Move it to the /app path. # Used for the fixed project to ensure consistent obfuscation results #-applymapping mapping.txt #hotfix -keep class com.taobao.sophix.**{*;} -keep class com.ta.utdid2.device.**{*;} # Prevent inlining -dontoptimizeImportantWhen you enable obfuscation, use the mapping file from the baseline package to generate the fix package. This ensures consistent obfuscation results.
Obfuscation with ProGuard
If you enable code obfuscation, you must disable R8 and use ProGuard instead. Otherwise, patch generation may fail. The specific steps depend on your Android Gradle Plugin version:
Android Gradle Plugin earlier than 7.0
In the `gradle.properties` file in the project's root directory, add the following configuration.
android.enableR8=falseAndroid Gradle Plugin 7.0 and later
In the `build.gradle` file in the project's root directory, add the following ProGuard Gradle Plugin configuration.
buildscript { repositories { // For the Android Gradle plugin. google() // For the ProGuard Gradle Plugin. mavenCentral() } dependencies { // The Android Gradle plugin. classpath("com.android.tools.build:gradle:x.y.z") // The ProGuard Gradle plugin. classpath("com.guardsquare:proguard-gradle:7.1.+") } }In the `build.gradle` file in the `app` folder, apply the ProGuard Gradle Plugin.
apply plugin: 'com.guardsquare.proguard'Then, disable R8 obfuscation.
android { buildTypes { release { // Disable R8. minifyEnabled false } } }Finally, configure ProGuard obfuscation.
android { ... } proguard { configurations { release { defaultConfiguration 'proguard-android.txt' configuration 'proguard-rules.pro' } debug { defaultConfiguration 'proguard-android-debug.txt' configuration 'proguard-rules.pro' } } }
Initialization
Call the initialization method as early as possible. You must initialize the SDK at the beginning of
Application.attachBaseContext(), after `super.attachBaseContext` and `Multidex.install` if you use Multidex. Do not use other custom classes before initialization, because this is very likely to cause a crash. You can query the server for available patches at a later point. We do not recommend initializing inApplication.onCreate(), because if the application includes a ContentProvider, Sophix initialization may be delayed and cause issues.The latest version of Sophix introduces a new initialization method.
The original initialization method still works. However, the new method provides more comprehensive support for feature fixes and offers the following advantages:
Initialization is completely isolated from the application's original business logic. This allows the original Application class to be patched and reduces the patch preloading time.
The new method is more compatible with Android 8.0 and later.
Specifically, you need to add the following class:
package com.my.pkg; import android.app.Application; import android.content.Context; import android.support.annotation.Keep; import android.util.Log; import com.taobao.sophix.PatchStatus; import com.taobao.sophix.SophixApplication; import com.taobao.sophix.SophixEntry; import com.taobao.sophix.SophixManager; import com.taobao.sophix.listener.PatchLoadStatusListener; import com.my.pkg.MyRealApplication; /** * Sophix entry class. This class is used only to initialize Sophix and should not contain any business logic. * This class must inherit from SophixApplication. You do not need to implement the onCreate method. * This class must be completely isolated and should not have any logic that calls or is called by other classes in the project. * In AndroidManifest, set the application to this class. In SophixEntry, set it to the original Application class. * Do not re-initialize Sophix in the original Application class. Make sure the original Application class is not obfuscated. * If you have other custom modifications, contact the official support team for proper handling. */ public class SophixStubApplication extends SophixApplication { private final String TAG = "SophixStubApplication"; // Here, SophixEntry should specify the real Application class, and you must ensure that the RealApplicationStub class name is not obfuscated. @Keep @SophixEntry(MyRealApplication.class) static class RealApplicationStub {} @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); // To use MultiDex, call it here. // MultiDex.install(this); initSophix(); } private void initSophix() { String appVersion = "0.0.0"; try { appVersion = this.getPackageManager() .getPackageInfo(this.getPackageName(), 0) .versionName; } catch (Exception e) { } final SophixManager instance = SophixManager.getInstance(); instance.setContext(this) .setUsingEnhance(true) // Adapts to reinforcement mode. Add this method if the app uses reinforcement. .setAppVersion(appVersion) .setSecretMetaData(null, null, null) .setEnableDebug(true) .setEnableFullLog() .setTags(Arrays.asList("Gray")) // Set tags as needed. .setPatchLoadStatusStub(new PatchLoadStatusListener() { @Override public void onLoad(final int mode, final int code, final String info, final int handlePatchVersion) { if (code == PatchStatus.CODE_LOAD_SUCCESS) { Log.i(TAG, "sophix load patch success!"); } else if (code == PatchStatus.CODE_LOAD_RELAUNCH) { // To restart the app in the background, we recommend that you use SharePreference to save the state here. Log.i(TAG, "sophix preload patch success. restart app to make effect."); } } }).initialize(); } }The key point is:
@Keep @SophixEntry(MyRealApplication.class) static class RealApplicationStub {}SophixEntry must specify the project's original Application class, which is specified by `android:name` in the `` tag. In this example, it is represented by `MyRealApplication`. Ensure that the
RealApplicationStubclass name is not obfuscated. You can choose your own class name and package name forSophixStubApplication.ImportantThe
SophixStubApplicationclass cannot contain any other logic. You can useSharedPreferencesto save the state.Here, Keep is a class from the `android.support` package. Its purpose is to prevent the name of this inner static class from being obfuscated, because Sophix uses reflection to retrieve the SophixEntry of this class. If your project does not have a dependency on `android.support`, you must manually specify in ProGuard that
RealApplicationStubshould not be obfuscated, as described below.Then, add the following content to the ProGuard file:
-keepclassmembers class com.my.pkg.MyRealApplication { public <init>(); } -keep class com.my.pkg.SophixStubApplication$RealApplicationStubThis prevents the constructor of the real Application class from being obfuscated by ProGuard.
Finally, change the application in `AndroidManifest` to this new SophixStubApplication class:
<application android:name="com.my.pkg.SophixStubApplication" ... ...> ... ...This completes the integration of the new initialization method.
Pull patches
After initialization is complete, you can query the server and pull a patch.
SophixManager.getInstance().queryAndLoadNewPatch();ImportantThe queryAndLoadNewPatch method is used to request patch packages published in the console. It initiates a network request, so it must be called after the user agrees to the privacy policy.
However, do not call this method in `attachBaseContext` because it will not have network permissions. We recommend that you call it at any point in the main process after the user agrees to the privacy policy.
Verify the integration
View the logs in Logcat to verify that the feature works. Filter by the tag `Sophix` and check for the following key log entries.
# Start pulling the patch Sophix.NetworkManager I query start # Successfully pulled the patch Sophix.NetworkManager I query download success # Start preloading the patch Sophix.ColdDexManager I preloadDex start sophix-merged.zip # Successfully preloaded the patch Sophix.ColdDexManager I preloadDex end time consumed(ms): 36064 # Successfully loaded the patch after a cold start Sophix.PatchManager I loadPatch success hasDexPatched: true hasResPatched: true hasSOPatched: false
If you encounter integration issues, first refer to the FAQ and Common status codes. If you cannot resolve the issue using the documentation, contact us.
Learning materials
In-depth Exploration of Android Hotfix Technology Principles — The industry's first book to systematically introduce hotpatching principles, offering an authoritative interpretation from the perspective of the Alibaba Sophix solution's development.
If you have other unofficial materials, contact us to join our DingTalk group. Share your articles with us, and we will select high-quality articles to feature here.