{"id":19510826,"url":"https://github.com/smuyyh/incrementallyupdate","last_synced_at":"2026-03-12T10:08:39.326Z","repository":{"id":108853222,"uuid":"62768536","full_name":"smuyyh/IncrementallyUpdate","owner":"smuyyh","description":"Android 应用增量更新","archived":false,"fork":false,"pushed_at":"2016-09-06T06:15:19.000Z","size":1465,"stargazers_count":179,"open_issues_count":3,"forks_count":68,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-04-26T03:44:50.046Z","etag":null,"topics":["android","incremental","update"],"latest_commit_sha":null,"homepage":"http://blog.csdn.net/yyh352091626/article/details/50579859","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/smuyyh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2016-07-07T02:31:33.000Z","updated_at":"2024-01-20T06:37:01.000Z","dependencies_parsed_at":"2023-04-15T22:47:01.719Z","dependency_job_id":null,"html_url":"https://github.com/smuyyh/IncrementallyUpdate","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/smuyyh/IncrementallyUpdate","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smuyyh%2FIncrementallyUpdate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smuyyh%2FIncrementallyUpdate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smuyyh%2FIncrementallyUpdate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smuyyh%2FIncrementallyUpdate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/smuyyh","download_url":"https://codeload.github.com/smuyyh/IncrementallyUpdate/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smuyyh%2FIncrementallyUpdate/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266135685,"owners_count":23881803,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","incremental","update"],"created_at":"2024-11-10T23:17:49.906Z","updated_at":"2026-03-12T10:08:39.035Z","avatar_url":"https://github.com/smuyyh.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# IncrementallyUpdate\nAndroid 实现应用的增量更新和升级\n\n### 原理\n服务端通过新版本APK和旧版本APK生成patch补丁（也成为差分包），客户端更新的时候只需要下载差分包到本地，然后从system/app取出旧版本APK，通过差分包来合成新版本的APK，这个过程实际上就是打补丁。\n\n步骤 | 内容\n---|---\n拷贝资源 | 拷贝旧版本APK以及新版本APK到SD卡。为了后面进行生成差分包\n安装旧版本APK | 安装旧版本的APK\n生成补丁 | 生成差分包。这个实际上应该是在服务端完成\n打补丁 | 通过差分包及旧版本APK生成新版本APK\n安装新版本APK | 安装生成的新版本APK\n获取某个应用的APK安装文件 | 在真正的增量更新过程中，旧版本Apk应该从/data/app底下获取，拷贝到SD卡，进行打补丁。当然，也可以不拷贝，直接使用该路径。\n\n\n```java\nString srcDir = Environment.getExternalStorageDirectory().toString() + \"/DaemonProcess-1.apk\";\nString destDir1 = Environment.getExternalStorageDirectory().toString() + \"/DaemonProcess-2.apk\";\nString destDir2 = Environment.getExternalStorageDirectory().toString() + \"/DaemonProcess-3.apk\";\nString patchDir = Environment.getExternalStorageDirectory().toString() + \"/DaemonProcess.patch\";\n```\n首先来看看这四个文件的作用\n\nsrcDir：旧版本apk路径。也就是已安装的旧版应用的APK地址。为了便于演示，这边直接写死路径。若想真正获取旧版apk地址，可通过下面代码实现：\n```java\nString appDir = getPackageManager().getApplicationInfo(packageName, 0).sourceDir;\n```\ndestDir1：新版本的apk路径。\n\ndestDir2：新版本的apk路径。通过差分包+旧版本APK合成新版本APK。\n\npatchDir：差分包。通过旧版本APK+新版本APK生成差分包。\n\n### NDK配置\n若需自己编译jni代码，则下载NDK，并在local.properties下配置自己ndk路径\n```xml\nndk.dir=/Users/yuyuhang/Documents/Android/android-ndk-r10c\n```\nbuild.gradle加入以下内容：\n```java\nandroid {\n    defaultConfig {\n        ndk{\n            moduleName \"ApkPatchLibrary\"\n            abiFilters \"armeabi\", \"armeabi-v7a\", \"x86\"\n        }\n    }\n    sourceSets {\n        main {\n            jni.srcDirs = ['src/main/jni', 'src/main/jni/']\n        }\n    }\n}\n```\n若不想编译jni资源，也可直接使用项目提供的so库。在build.gradle配置so库路径,去掉jni编译相关脚本，sync now...\n```java\nsourceSets {\n        main {\n            // jni.srcDirs = ['src/main/jni', 'src/main/jni/']\n            jniLibs.srcDirs = ['libs'] // 若不想编译jni代码，可直接引用so库，ndk编译相关脚本注释掉\n        }\n    }\n```\n\n### 使用\n调用生成差分包及合成APK的native方法。\n```java\npackage com.yyh.lib.bsdiff;\n\npublic class DiffUtils {\n\n\tstatic DiffUtils instance;\n\n\tpublic static DiffUtils getInstance() {\n\t\tif (instance == null)\n\t\t\tinstance = new DiffUtils();\n\t\treturn instance;\n\t}\n\n\tstatic {\n\t\tSystem.loadLibrary(\"ApkPatchLibrary\");\n\t}\n\n\t/**\n\t * 比较oldapk与newapk之间差异，并生成patch包，存储于patchPath\n\t * \n\t * @param oldApkPath 示例:/sdcard/old.apk\n\t * @param newApkPath 示例:/sdcard/new.apk\n\t * @param patchPath 示例:/sdcard/xx.patch\n\t * @return 0:成功 非0:失败\n\t */\n\tpublic native int genDiff(String oldApkPath, String newApkPath, String patchPath);\n}\n```\n```java\npackage com.yyh.lib.bsdiff;\n\npublic class PatchUtils {\n\n\tstatic PatchUtils instance;\n\n\tpublic static PatchUtils getInstance() {\n\t\tif (instance == null)\n\t\t\tinstance = new PatchUtils();\n\t\treturn instance;\n\t}\n\n\tstatic {\n\t\tSystem.loadLibrary(\"ApkPatchLibrary\");\n\t}\n\n\t/**\n\t * 使用oldApk与patch补丁包，合成新的apk，存储于newApkPath\n\t * \n\t * @param oldApkPath 示例:/sdcard/old.apk\n\t * @param newApkPath 示例:/sdcard/new.apk\n\t * @param patchPath 示例:/sdcard/xx.patch\n\t * @return 0:成功 非0:失败\n\t */\n\tpublic native int patch(String oldApkPath, String newApkPath, String patchPath);\n}\n```\n\n### 服务端\n服务端工具以及源码位于Server目录下。目前只在Linux64位的系统下编译，其他系统大家可自行编译。Linux下的可直接修改makefile，windows下可用VC编译。\n\n###### Diff工具：生成差分包\n```xml\n\u003c!--命令             oldApk              newApk              patch--\u003e\n./linux-x86_64/Diff DaemonProcess-1.apk DaemonProcess-2.apk dp.patch\n```\n###### Patch工具：合并\n\n```xml\n\u003c!--命令              oldApk              newApk              patch--\u003e\n./linux-x86_64/Patch DaemonProcess-1.apk DaemonProcess-3.apk dp.patch\n```\n\n\n### 项目截图\n\n\u003cimg src=\"https://github.com/smuyyh/IncrementallyUpdate/blob/master/screenshot/1.png?raw=true\" width=\"280\"/\u003e\n\u003cimg src=\"https://github.com/smuyyh/IncrementallyUpdate/blob/master/screenshot/3.png?raw=true\" width=\"280\"/\u003e\n\u003cimg src=\"https://github.com/smuyyh/IncrementallyUpdate/blob/master/screenshot/2.png?raw=true\" width=\"280\"/\u003e","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmuyyh%2Fincrementallyupdate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsmuyyh%2Fincrementallyupdate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmuyyh%2Fincrementallyupdate/lists"}