# NpHotfixExample **Repository Path**: incachina_0/NpHotfixExample ## Basic Information - **Project Name**: NpHotfixExample - **Description**: 印加时代热更SDK示例项目 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: download - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-09-23 - **Last Updated**: 2025-06-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## NpHotfix - 1. java 版本需要使用java17或以上 - 2. Android minSdk 设置为 23 ## 示例项目运行 `main`分支的代码是在`/sdcard/`中加载升级补丁。`download`分支的代码是通过调用云api下载升级文件。 ### 项目配置文件 #### `buildScripts/nphotfix.properties` - 1. sevenZip:7zip执行文件的绝对路径。修改为在自己系统的路径。 - 2. isBaseBuild:第一次生成基础包编译的时候修改为1,其他版本的时候修改为0。 - 3. baseApkName:基础包名称。当云服务端上传大版本的时候,此处需要设置与其名称相同。 - 4. versionCode:版本号。每次发版的时候需要修改,建议修改值为累加1。 - 5. versionName:版本名称。每次发版的时候需要修改,建议修改值为累加0.1。 #### `buildScripts/ext.gradle` - 1. nphotfixVersion:NpHotfix SDK版本号设置。 - 2. CHANNEL:渠道ID设置,找印加客服申请。 - 3. SPEED_UP: 设置快速更新不进行文件验证工作,请务必保证更新包的正确。(如果设置非1的数值会执行更新前的文件验证工作,验证工作需要耗时更新时间为1-2分钟。) #### `buildScripts/appguard.gradle` - 1. IS_ENABLE_APPGUARD:设置为1表示启用appguard,设置为0表示禁用appguard。 ### `linux/macos`开发环境可以通过运行脚本快速构建程序并运行。 ```bash # 运行run_host.sh生成基础包。 # -r 参数表示 构建类型为release. # -b 参数表示 生成基础包. # -g 参数表示 启用appguard. # 此脚本中自动修改了nphotfix.properties的baseApkName, isBaseBuild, versionCode,versionName ./run_host.sh -r -b # 生成补丁包,并自动推送到/sdcard/ # 此脚本中自动修改了nphotfix.properties的isBaseBuild, versionCode, versionName ./host_patch.sh ``` ### `windows`开发环境 修改 `buildScripts/nphotfix.properties`(注意需要添加转义字符): __sevenZip=E\\:\\\7z安装路径\\\7z.exe__ ```bat # 生成基础包 .\gradlew.bat clean .\gradlew.bat assembleRelease # 生成补丁包 .\gradlew.bat tinkerPatchRelease ``` 点击示例程序界面的 “Start Upgrade”,开始下载补丁app,当补丁安装完成后点击"Exit"并再次打开应用可查看界面的变化。 点击"Start Upgrade"升级补丁程序时,请查看logcat的日志,会有详细的一些进度输出。 ## SDK接入使用 - 1. 将示例代码中的`buildScripts`文件复制到项目根目录中. - 2. 将示例代码中的**proguard-rules.pro**, **tinker_multidexkeep.pro**文件复制到`app`项目目录下。 请注意在 `tinker_multidexkeep.pro`文件中关于**dex.loader** 的**com.inca.ota.example ExampleApplication**包名需要替换成自己项目的包名如:**com.mfyndk.testhotfix.MyApplication** - 3. 在 `setting.gradle` 中添加以下内容: ```gradle //分别在 pluginManagement 和 dependencyResolutionManagement的repositories标签中添加阿里云仓库。 repositories { maven { url 'https://maven.aliyun.com/repository/public' } maven { credentials { username = '66b5bdba2f2dfc5fa22a09ca' password = 'jEpfL=_VG[[C' } url 'https://packages.aliyun.com/maven/repository/2486498-snapshot-3nBXCQ' } } ``` - 4. 在项目根目录中的 `build.gradle` 文件中添加以下内容: ```gradle //添加 ext.gradle和classpath buildscript { apply from: 'buildScripts/ext.gradle' dependencies { classpath ("com.inca.ota:inca-ota-gradle:$nphotfixVersion") } } ``` - 5. 在 `app/build.gradle`文件中添加以下内容: ```gradle //添加inca-ota-gradle插件 plugins { //在application下面添加 id 'com.inca.ota.host' } android { defaultConfig { //为支持tinker 需要设置23,不能大于24 minSdk 23 //读取nphotfix.properties中的versionCode,versionName versionCode project.ext.versionCode versionName "${project.ext.versionName}" //设置 multidex和proguard multiDexEnabled true multiDexKeepProguard file("tinker_multidexkeep.pro") //设置AndroidManifest.xml的动态环境变量 manifestPlaceholders = [cleartextTrafficPermitted:"true", channel:"${rootProject.ext.CHANNEL}", tinkerId:"${project.android.defaultConfig.versionName}_${project.android.defaultConfig.versionCode}", speedUp:"${rootProject.ext.SPEED_UP}", apiHost:"${rootProject.ext.SERVER_API_URL}"] } //设置自己的签名,这个签名要与热更后台设置的签名sha1值相同。 //在项目根目录下自定义文件夹keystore,将签名放到此文件夹下并进行设置以下签名信息。 signingConfigs { release { try { //替换为你的签名私钥口令 storeFile file("$rootDir/keystore/debug.keystore") storePassword "xxxxx" keyAlias "xxxxx" keyPassword "xxxx" } catch (ex) { throw new InvalidUserDataException(ex.toString()) } } debug { //替换为你的签名私钥口令 storeFile file("$rootDir/keystore/debug.keystore") storePassword "xxxxx" keyAlias "xxxxx" keyPassword "xxxx" } } buildFeatures { //生成BuildConfig.java buildConfig true } buildTypes { release { //启用proguard minifyEnabled true //指定proguard文件 proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' //启用签名 signingConfig signingConfigs.release } } } //添加依赖组件 dependencies { compileOnly("com.inca.ota:inca-ota-gradle:$nphotfixVersion") implementation("com.inca.ota:nphotfix:$nphotfixVersion"){ changing = true } implementation "androidx.multidex:multidex:2.0.1" } //添加构建appguard的脚本 apply from: "$rootDir/buildScripts/appguard.gradle" ``` - 6. 创建热更时需要的Application,注意注入标签`DefaultLifeCycle`的application属性的字符串值修改,并且其字符串值与`AndroidManifest.xml`中Application name值保持一致。 示例中是`ExampleApplicationLike.java`,请注意务必创建的这个Application末尾需要添加`Like`,但在`DefaultLifeCycle`和`AndroidManifest.xml`中配置时不需要添加`Like`。 ```java package com.inca.ota.example; import android.annotation.TargetApi; import android.app.Application; import android.content.Context; import android.content.Intent; import android.os.Build; import androidx.multidex.MultiDex; import com.inca.ota.tinker.HostOta; import com.tencent.tinker.anno.DefaultLifeCycle; import com.tencent.tinker.entry.DefaultApplicationLike; import com.tencent.tinker.loader.shareutil.ShareConstants; @SuppressWarnings("unused") @DefaultLifeCycle(application = "com.inca.ota.example.ExampleApplication", //这个理需要替换成项目中自己的包名+Application name,这个Application name不能添加Like flags = ShareConstants.TINKER_ENABLE_ALL, loadVerifyFlag = false) public class ExampleApplicationLike extends DefaultApplicationLike { public ExampleApplicationLike(Application application, int tinkerFlags, boolean tinkerLoadVerifyFlag, long applicationStartElapsedTime, long applicationStartMillisTime, Intent tinkerResultIntent) { super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent); } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Override public void onBaseContextAttached(Context base) { super.onBaseContextAttached(base); MultiDex.install(base); HostOta.get().init(getApplication(), this); } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public void registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks callback) { getApplication().registerActivityLifecycleCallbacks(callback); } @Override public void onCreate() { super.onCreate(); System.loadLibrary("testhotfix"); } } ``` - 7. 在 `AndroidManifest.xml`中进行如下设置: ```xml ``` - 8. 创建 file_paths.xml `app/res/xml/*.xml` ```xml ``` - 9. 在启动页的activity中添加热更启动初始化代码,参考示例中的`MainActivity.java`文件 ```java //main分支的示例代码:在/sdcard中加载补丁包. TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(), Environment.getExternalStorageDirectory().getAbsolutePath() + "/app-"+com.inca.ota.example.host.BuildConfig.BUILD_TYPE+"-patch_signed_7zip.apk"); //download分支的代码:通过调用云api下载升级文件. HostUpgrade.get().getNew(HostUpgrade.VERSION_TYPE_APP, MainActivity.this, new UpgradeCallback() { @Override public void onFinished() { MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { mBtnStartUpgrade.setEnabled(true); } }); } public void onError() { MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(MainActivity.this,"download error ...", Toast.LENGTH_LONG).show(); mBtnStartUpgrade.setEnabled(true); } }); } }); //请求存储读写权限,Android11以上和旧版本有些不同,具体参考示例代码。 if(!hasRequiredPermissions()) { requestForStoragePermissions(); } ``` - 10. 升级下载安装的进度状态,参考`MainActivity`中的实现。 ```java //升级文件下载时的进度状态显示函数 @Override public void onDownloadProgress(int versionType ,long currentOffset, long totalLength) { } //热补丁安装的进度状态显示函数 @Subscribe(threadMode = ThreadMode.MAIN) public void onPatchReslutEvent(PatchResultEvent event){ Log.i(TAG,"onPatchReslutEvent ..."); if (mProgressInstallPatch.isShowing()) { mProgressInstallPatch.dismiss(); } } @Override protected void onStart() { super.onStart(); EventBus.getDefault().register(this); } @Override protected void onStop() { super.onStop(); EventBus.getDefault().unregister(this); } ```