{"id":2175,"date":"2023-05-01T10:20:45","date_gmt":"2023-05-01T02:20:45","guid":{"rendered":"https:\/\/www.appblog.cn\/?p=2175"},"modified":"2024-01-13T23:37:34","modified_gmt":"2024-01-13T15:37:34","slug":"android-incremental-update-client-merge-bsdiff-differential-package-with-original-package","status":"publish","type":"post","link":"https:\/\/www.appblog.cn\/index.php\/2023\/05\/01\/android-incremental-update-client-merge-bsdiff-differential-package-with-original-package\/","title":{"rendered":"Android\u589e\u91cf\u66f4\u65b0 &#8211; \u5ba2\u6237\u7aef\u4f7f\u7528bsdiff\u5dee\u5206\u5305\u4e0e\u539f\u5305\u5408\u5e76"},"content":{"rendered":"<h2>bsdiff\u7b80\u4ecb<\/h2>\n<p>Android\u589e\u91cf\u66f4\u65b0\u9700\u8981\u7528\u5230\u4e8c\u8fdb\u5236\u5dee\u5206\u5de5\u5177\uff1absdiff<\/p>\n<p>bsdiff and bspatch are tools for building and applying patches to binary files.<\/p>\n<p>\u5b98\u65b9\u7f51\u7ad9\uff1a<a target=\"_blank\" rel=\"noopener\" href=\"http:\/\/www.daemonology.net\/bsdiff\/\">http:\/\/www.daemonology.net\/bsdiff\/<\/a><br \/>\nbsdiff for windows\uff1a<a target=\"_blank\" rel=\"noopener\" href=\"http:\/\/www.pokorra.de\/coding\/bsdiff.html\">http:\/\/www.pokorra.de\/coding\/bsdiff.html<\/a><\/p>\n<h2>Android\u7248\u672c\u533a\u522b\u8bbe\u5b9a<\/h2>\n<p>\uff081\uff09\u65e7\u7248\u672c<\/p>\n<p>app.gradle<\/p>\n<pre><code>versionCode 1\nversionName &quot;1.0&quot;<\/code><\/pre>\n<p>activity_main.xml<\/p>\n<pre><code class=\"language-xml\">&lt;TextView\n    android:layout_width=&quot;wrap_content&quot;\n    android:layout_height=&quot;wrap_content&quot;\n    android:layout_gravity=&quot;center_horizontal&quot;\n    android:layout_marginTop=&quot;20dp&quot;\n    android:text=&quot;1.0\u7248\u672c&quot;\n    android:textSize=&quot;16sp&quot;\n    android:textColor=&quot;#3BC1FF&quot;\n    \/&gt;<\/code><\/pre>\n<p>\uff082\uff09\u65b0\u7248\u672c<\/p>\n<p>\u6dfb\u52a0\u8d44\u6e90\u6587\u4ef6\uff1aassets\/cctv.mp4<\/p>\n<p>app.gradle<\/p>\n<pre><code>versionCode 2\nversionName &quot;2.0&quot;<\/code><\/pre>\n<p>activity_main.xml<\/p>\n<pre><code class=\"language-xml\">&lt;TextView\n    android:layout_width=&quot;wrap_content&quot;\n    android:layout_height=&quot;wrap_content&quot;\n    android:layout_gravity=&quot;center_horizontal&quot;\n    android:layout_marginTop=&quot;20dp&quot;\n    android:text=&quot;2.0\u7248\u672c&quot;\n    android:textSize=&quot;16sp&quot;\n    android:textColor=&quot;#3BC1FF&quot;\n    \/&gt;<\/code><\/pre>\n<h2>NDK\u5b9e\u73b0pacth<\/h2>\n<h3>Java\u5c42\u58f0\u660enative\u65b9\u6cd5<\/h3>\n<pre><code class=\"language-java\">public class BsPatch {\n\n    \/**\n     * \u5408\u5e76\n     * @param oldFilePath\n     * @param newFilePath\n     * @param patchFilePath\n     *\/\n    public static native void patch(String oldFilePath, String newFilePath, String patchFilePath);\n\n    static {\n        System.loadLibrary(&quot;BsPatch&quot;);\n    }\n}<\/code><\/pre>\n<h3>C\u5c42\u5408\u5e76\u7b97\u6cd5\u5b9e\u73b0\uff1adiffupdate.c<\/h3>\n<p><div class=\"erphp-wppay payme payme-center\">\r\n                <div class=\"payme-toggle\">\r\n                <div id=\"wppay-payment-todo\" style=\"display: inline\">\r\n                  \u60a8\u9700\u8981\u5148\u652f\u4ed8 <b>1\u5143<\/b> \u624d\u80fd\u67e5\u770b\u6b64\u5904\u5185\u5bb9\uff01<br\/><br\/><a href=\"javascript:;\" class=\"erphp-wppay-loader btn btn-link\" data-post=\"2175\"><span style=\"color: white; \">\u7acb\u5373\u652f\u4ed8<\/span><\/a><br\/>\r\n                  <a id=\"wppay-query-link\" href=\"javascript:;\">\u5df2\u652f\u4ed8\uff1f\u70b9\u51fb\u8fd9\u91cc\u67e5\u8be2<\/a>\r\n                <\/div>\r\n\t\t\t\t<div id=\"wppay-payment-query\" style=\"display: none\">\r\n\t\t\t\t  <div id=\"wppay-query-form\">\r\n                    <input type=\"hidden\" name=\"post_id\" value=\"2175\">\r\n                    <input type=\"hidden\" name=\"post_title\" value=\"\">\r\n                    <input type=\"hidden\" name=\"post_url\" value=\"\">\r\n                    <input type=\"hidden\" name=\"post_price\" value=\"5.00\">\r\n                    <div>\r\n                        <label for=\"query_string\">\u5546\u5bb6\u8ba2\u5355\u53f7\/\u8ba2\u5355\u53f7\uff1a<\/label>\r\n                        <input type=\"text\" id=\"order_num\" name=\"order_num\" style=\"width:300px\" aria-required=\"true\" aria-invalid=\"true\" autofocus=\"\" placeholder=\"\u5546\u5bb6\u8ba2\u5355\u53f7\/\u8ba2\u5355\u53f7\">\r\n                        <button class=\"btn payme-btn\" name=\"button\" id=\"do-payment-query\"><span style=\"color: white; \">\u67e5 \u8be2<\/span><\/button>\r\n                    <\/div>\r\n                    <div>\r\n                        \uff08<a id=\"wppay-alipay-help-link\" href=\"javascript:;\">\u5982\u4f55\u67e5\u770b\u5546\u5bb6\u8ba2\u5355\u53f7\/\u8ba2\u5355\u53f7?<\/a>\uff09<br\/>\r\n                        <a id=\"wppay-pay-link\" href=\"javascript:;\">\u8fd4\u56de\u7ee7\u7eed\u652f\u4ed8<\/a><br\/>\r\n                        <div id=\"alipay-get-out-trade-no\" style=\"display: none;\">\r\n                          <br\/>\r\n                          <img decoding=\"async\" style=\"max-width: 100%\" src=\"\/wp-content\/uploads\/2024\/01\/get_alipay_out_trade_no.png\" alt=\"\"\/>\r\n                        <\/div>\r\n                    <\/div>\r\n                  <\/div>\r\n                <\/div>\r\n\t\t\t<\/div><\/div><\/p>\n<h3>Java\u5c42\u8c03\u7528bspatch\u5b9e\u73b0bsdiff\u5dee\u5206\u5305\u4e0e\u539f\u5305\u5408\u5e76<\/h3>\n<pre><code class=\"language-java\">class AppUpdateTask extends AsyncTask&lt;Void, Void, Boolean&gt; {\n    @Override\n    protected Boolean doInBackground(Void... params) {\n        \/\/1. \u4e0b\u8f7d\u5dee\u5206\u5305\n        Log.i(TAG, &quot;\u5f00\u59cb\u4e0b\u8f7d&quot;);\n        \/\/File patchFile = DownloadUtil.download(PATCH_URL);\n        \/\/String patchFilePath = patchFile.getAbsolutePath();\n        Log.i(TAG, &quot;\u4e0b\u8f7d\u5b8c\u6210&quot;);\n        \/\/2. \u83b7\u53d6\u65e7\u7248\u672c\u5df2\u7ecf\u5b89\u88c5\u7684apk\u6587\u4ef6(\/data\/app\/)\n        String oldApk = ApkUtil.getSourceApkPath(MainActivity.this, getPackageName());\n        Log.i(TAG, &quot;Old Apk: &quot; + oldApk);\n        \/\/3. \u5408\u5e76\uff1aoldFile+patchFile-&gt;newFile\n        BsPatch.patch(oldApk, NEW_APK_PATH, PATCH_FILE_PATH);\n        Log.i(TAG, &quot;\u5408\u5e76\u5b8c\u6210&quot;);\n        try {\n            Log.i(TAG, &quot;New Apk MD5: &quot; + MD5Util.getFileMD5String(NEW_APK_PATH));\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        return true;\n    }\n\n    @Override\n    protected void onPostExecute(Boolean result) {\n        super.onPostExecute(result);\n        if (!result) {\n            Toast.makeText(MainActivity.this, &quot;\u5dee\u5206\u5305\u5408\u5e76\u5931\u8d25&quot;, Toast.LENGTH_SHORT).show();\n        }\n        \/\/1. \u83b7\u53d6\u4e24\u4e2a\u7248\u672c\u7684\u7b7e\u540d\u8fdb\u884c\u5bf9\u6bd4\n        \/\/\u83b7\u53d6\u5df2\u7ecf\u5b89\u88c5\u5e94\u7528\u7684\u7b7e\u540d\n        String oldSign = SignUtil.getInstalledApkSignature(MainActivity.this, getPackageName());\n        \/\/\u83b7\u53d6\u672a\u5b89\u88c5Apk\u6587\u4ef6\u7684\u7b7e\u540d\n        String newSign = SignUtil.getUnInstalledApkSignature(NEW_APK_PATH);\n        if (TextUtils.equals(newSign, oldSign)) {\n            \/\/2. \u5b89\u88c5\n            ApkUtil.installApk(MainActivity.this, NEW_APK_PATH);\n        } else {\n            Toast.makeText(MainActivity.this, &quot;\u7b7e\u540d\u4e0d\u5339\u914d&quot;, Toast.LENGTH_SHORT).show();\n        }\n        Toast.makeText(MainActivity.this, &quot;\u5dee\u5206\u5305\u5408\u5e76\u6210\u529f&quot;, Toast.LENGTH_SHORT).show();\n    }\n}<\/code><\/pre>\n<h3>app.gradle \u914d\u7f6e<\/h3>\n<pre><code>defaultConfig {\n    ...\n    externalNativeBuild {\n        cmake {\n            cppFlags &quot;-frtti -fexceptions&quot;\n            abiFilters &#039;x86&#039;, &#039;x86_64&#039;, &#039;armeabi&#039;, &#039;armeabi-v7a&#039;, &#039;arm64-v8a&#039;\n        }\n    }\n}\n\nexternalNativeBuild {\n    cmake {\n        path &quot;CMakeLists.txt&quot;\n    }\n}<\/code><\/pre>\n<h3>\u5b89\u88c5\u6d4b\u8bd5<\/h3>\n<pre><code>> adb push diff.patch \/sdcard\/  \/\/\u5c06\u5dee\u5206\u5305\u5bfc\u5165\u5230SD\u5361\u4e2d\uff0c\u6a21\u62df\u5728\u7ebf\u66f4\u65b0\n[100%] \/sdcard\/diff.patch\n\n> adb install DiffUpdate_v1.apk  \/\/\u5b89\u88c5\u65e7\u7248Apk\u4ee5\u5f85\u6d4b\u8bd5\u589e\u91cf\u66f4\u65b0\n[100%] \/data\/local\/tmp\/DiffUpdate_v1.apk\n        pkg: \/data\/local\/tmp\/DiffUpdate_v1.apk\nSuccess\n\n><\/code><\/pre>\n<p>\u8fd0\u884c\u65e5\u5fd7\u8f93\u51fa\uff0c\u53ef\u4ee5\u770b\u5230\u5408\u5e76\u751f\u6210\u7684 New Apk MD5 \u4e0e\u670d\u52a1\u5668\u7aef\u5408\u5e76\u751f\u6210\u7684\u5b8c\u5168\u4e00\u81f4<\/p>\n<pre><code>cc.androidios.diffupdate I\/yezhou: Old Apk: \/data\/app\/cc.androidios.diffupdate-1\/base.apk\ncc.androidios.diffupdate I\/yezhou: \u5408\u5e76\u5b8c\u6210\ncc.androidios.diffupdate I\/yezhou: New Apk MD5: 735a02764167048e738a7f6ea99f2b86<\/code><\/pre>\n<h2>\u6838\u5fc3\u6280\u672f\u70b9<\/h2>\n<h3>bspatch\u529f\u80fd\u8c03\u7528<\/h3>\n<p>bspatch\u7684\u4f7f\u7528\u65b9\u6cd5\u4e3a<\/p>\n<pre><code>bspatch oldfile newfile patchfile<\/code><\/pre>\n<p>bspatch.c\u7684main\u51fd\u6570\u4e3a\u5176\u5165\u53e3\u51fd\u6570\uff0c\u8fd9\u91cc\u5c06\u51fd\u6570\u540d\u6539\u4e3abspatch_main\uff0c\u53d8\u4e3a\u666e\u901a\u51fd\u6570\uff0c\u5373\u53ef\u5b9e\u73b0\u88ab\u5176\u5b83\u51fd\u6570\u8c03\u7528\u3002<\/p>\n<pre><code class=\"language-c\">int bspatch_main(int argc, char * argv[])<\/code><\/pre>\n<h3>CMakeLists.txt \u914d\u7f6e<\/h3>\n<p><div class=\"erphp-wppay payme payme-center\">\r\n                <div class=\"payme-toggle\">\r\n                <div id=\"wppay-payment-todo\" style=\"display: inline\">\r\n                  \u60a8\u9700\u8981\u5148\u652f\u4ed8 <b>1\u5143<\/b> \u624d\u80fd\u67e5\u770b\u6b64\u5904\u5185\u5bb9\uff01<br\/><br\/><a href=\"javascript:;\" class=\"erphp-wppay-loader btn btn-link\" data-post=\"2175\"><span style=\"color: white; \">\u7acb\u5373\u652f\u4ed8<\/span><\/a><br\/>\r\n                  <a id=\"wppay-query-link\" href=\"javascript:;\">\u5df2\u652f\u4ed8\uff1f\u70b9\u51fb\u8fd9\u91cc\u67e5\u8be2<\/a>\r\n                <\/div>\r\n\t\t\t\t<div id=\"wppay-payment-query\" style=\"display: none\">\r\n\t\t\t\t  <div id=\"wppay-query-form\">\r\n                    <input type=\"hidden\" name=\"post_id\" value=\"2175\">\r\n                    <input type=\"hidden\" name=\"post_title\" value=\"\">\r\n                    <input type=\"hidden\" name=\"post_url\" value=\"\">\r\n                    <input type=\"hidden\" name=\"post_price\" value=\"5.00\">\r\n                    <div>\r\n                        <label for=\"query_string\">\u5546\u5bb6\u8ba2\u5355\u53f7\/\u8ba2\u5355\u53f7\uff1a<\/label>\r\n                        <input type=\"text\" id=\"order_num\" name=\"order_num\" style=\"width:300px\" aria-required=\"true\" aria-invalid=\"true\" autofocus=\"\" placeholder=\"\u5546\u5bb6\u8ba2\u5355\u53f7\/\u8ba2\u5355\u53f7\">\r\n                        <button class=\"btn payme-btn\" name=\"button\" id=\"do-payment-query\"><span style=\"color: white; \">\u67e5 \u8be2<\/span><\/button>\r\n                    <\/div>\r\n                    <div>\r\n                        \uff08<a id=\"wppay-alipay-help-link\" href=\"javascript:;\">\u5982\u4f55\u67e5\u770b\u5546\u5bb6\u8ba2\u5355\u53f7\/\u8ba2\u5355\u53f7?<\/a>\uff09<br\/>\r\n                        <a id=\"wppay-pay-link\" href=\"javascript:;\">\u8fd4\u56de\u7ee7\u7eed\u652f\u4ed8<\/a><br\/>\r\n                        <div id=\"alipay-get-out-trade-no\" style=\"display: none;\">\r\n                          <br\/>\r\n                          <img decoding=\"async\" style=\"max-width: 100%\" src=\"\/wp-content\/uploads\/2024\/01\/get_alipay_out_trade_no.png\" alt=\"\"\/>\r\n                        <\/div>\r\n                    <\/div>\r\n                  <\/div>\r\n                <\/div>\r\n\t\t\t<\/div><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>bsdiff\u7b80\u4ecb Android\u589e\u91cf\u66f4\u65b0\u9700\u8981\u7528\u5230\u4e8c\u8fdb\u5236\u5dee\u5206\u5de5\u5177\uff1absdiff bsdiff and bspat [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[346],"tags":[556],"class_list":["post-2175","post","type-post","status-publish","format-standard","hentry","category-open-source-compile","tag-bsdiff"],"_links":{"self":[{"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/posts\/2175","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/comments?post=2175"}],"version-history":[{"count":0,"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/posts\/2175\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/media?parent=2175"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/categories?post=2175"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/tags?post=2175"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}