{"id":2911,"date":"2020-07-17T16:00:59","date_gmt":"2020-07-17T08:00:59","guid":{"rendered":"https:\/\/learn-house.idv.tw\/?p=2911"},"modified":"2020-07-22T16:03:59","modified_gmt":"2020-07-22T08:03:59","slug":"android%e5%af%a6%e7%8f%beapk%e9%9d%9c%e9%bb%98%e5%ae%89%e8%a3%9dsilent-install","status":"publish","type":"post","link":"https:\/\/learn-house.idv.tw\/?p=2911","title":{"rendered":"[Android]\u5be6\u73feAPK\u975c\u9ed8\u5b89\u88dd(Silent Install)"},"content":{"rendered":"<p>\u7576\u521d\u70ba\u4e86\u9054\u5230\u81ea\u52d5\u5b89\u88ddAPK\uff0c\u800c\u4e0d\u6703\u8df3\u51fa\u4efb\u4f55\u8a0a\u606f\uff0c\u4e14\u53c8\u4e0d\u80fd\u4f7f\u7528\u975e\u6cd5\u7684API\u6216Java Reflection\u3002<br \/>\n\u7814\u7a76\u8d85\u4e45\uff0c\u8a66\u4e86\u7db2\u8def\u4e0a\u597d\u591a\u4eba\u7684\u505a\u6cd5\uff0c\u4e00\u76f4\u7121\u6cd5\u6210\u529f\uff0c\u76f4\u5230\u4ee5\u4e0b\u7684\u65b9\u6cd5\u624d\u6709\u6548\u9054\u5230\u6211\u60f3\u8981\u7684\u6548\u679c\u3002<br \/>\n\u7531\u65bc\u662f\u5f88\u4e45\u4ee5\u524d\u8a66\u51fa\u4f86\u7684\uff0c\u6211\u4e5f\u5fd8\u8a18\u51fa\u8655\u5728\u54ea\u4e86\uff0c\u70ba\u4e86\u9810\u9632\u54ea\u5929\u6211\u5beb\u7684\u7684\u6e2c\u8a66\u7a0b\u5f0f\u4e0d\u5c0f\u5fc3\u88ab\u6211\u6e05\u6389\u3002\u56e0\u6b64\u5728\u9019\u88e1\u5099\u4efd\u4e00\u4e0b\u7a0b\u5f0f\u78bc\u3002<br \/>\n<!--more--><br \/>\n[java]<br \/>\nprivate void autoInstall(Context context) {<br \/>\n\tString apkfile = context.getFilesDir() + &quot;\/MyTest.apk&quot;;<br \/>\n\tString ACTION_INSTALL_COMPLETE = &quot;cm.android.intent.action.INSTALL_COMPLETE&quot;;<br \/>\n\ttry {<br \/>\n\t\tPackageInstaller pi = context.getPackageManager().getPackageInstaller();<br \/>\n\t\t\/\/\u7d66\u5b9a\u6a21\u5f0f\uff0c\u5275\u5efa\u65b0\u7684\u53c3\u6578\uff0c\u5275\u5efa\u65b0\u5b89\u88dd\u6703\u8a71\uff0c\u8fd4\u56de\u552f\u4e00 Id<br \/>\n\t\tint sessionId= pi.createSession(new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL));<br \/>\n\t\t\/\/\u6253\u958b\u73fe\u6709\u6703\u8a71\uff0c\u4e3b\u52d5\u57f7\u884c\u5de5\u4f5c<br \/>\n\t\tPackageInstaller.Session session = pi.openSession(sessionId);<br \/>\n\t\tlong sizeBytes = 0;<br \/>\n\t\tfinal File file = new File(apkfile);<br \/>\n\t\tif (file.isFile()) {<br \/>\n\t\t\tsizeBytes = file.length();<br \/>\n\t\t}<br \/>\n\t\tInputStream in = null;<br \/>\n\t\tOutputStream out = null;<br \/>\n\t\tin = new FileInputStream(apkfile);<br \/>\n\t\t\/\/\u6253\u958b\u4e00\u500b\u6d41\uff0c\u5c07\u4e00\u500bAPK\u6587\u4ef6\u5beb\u5165\u6703\u8a71<br \/>\n\t\t\/\/\u6307\u5b9a\u6709\u6548\u9577\u5ea6\u7cfb\u7d71\u5c07\u9810\u5148\u5206\u914d\u5e95\u5c64\u78c1\u76e4\u7a7a\u9593\u4ee5\u512a\u5316\u78c1\u76e4\u4e0a\u7684\u653e\u7f6e<br \/>\n\t\tout = session.openWrite(&quot;app_store_session&quot;, 0, sizeBytes);<br \/>\n\t\tint total = 0;<br \/>\n\t\tbyte[] buffer = new byte[65536];<br \/>\n\t\tint len;<br \/>\n\t\twhile ((len= in.read(buffer)) != -1) {<br \/>\n\t\t\ttotal += len;<br \/>\n\t\t\tout.write(buffer, 0, len);<br \/>\n\t\t}<br \/>\n\t\t\/\/\u6839\u64da\u9700\u8981\u8abf\u7528\uff0c\u7528\u4f86\u78ba\u4fdd\u5b57\u7bc0\u5df2\u4fdd\u7559\u5230\u78c1\u76e4<br \/>\n\t\tsession.fsync(out);<br \/>\n\t\tin.close();<br \/>\n\t\tout.close();<br \/>\n\t\tLog.d(TAG,&quot;InstallApkViaPackageInstaller &#8211; Success: streamed apk &quot; + total + &quot; bytes&quot;);<br \/>\n\t\tPendingIntent broadCastTest = PendingIntent.getBroadcast(<br \/>\n\t\t\t\tcontext,<br \/>\n\t\t\t\tsessionId,<br \/>\n\t\t\t\tnew Intent(ACTION_INSTALL_COMPLETE),<br \/>\n\t\t\t\tPendingIntent.FLAG_UPDATE_CURRENT);<br \/>\n\t\t\/\/\u63d0\u4ea4\u4e4b\u524d\u5fc5\u9808\u95dc\u9589\u6240\u6709\u6d41<br \/>\n\t\tsession.commit(broadCastTest.getIntentSender());<br \/>\n\t\tsession.close();<br \/>\n\t} catch (Exception ex) {<br \/>\n\t\tex.printStackTrace();<br \/>\n\t}<br \/>\n}<br \/>\n[\/java]<br \/>\n\u7531\u65bcapk\u9808\u653e\u7f6e\u5728\u4f60\u57f7\u884c\u7684APP\u4e0b\uff0c\u56e0\u6b64\u8981\u5728\u57f7\u884c\u7684app\u5efa\u7acbassets\uff0c\u8907\u88fd\u5230\/data\/data\/< package name >\/files\/\u2026<br \/>\n\u505a\u6cd5\u5982\u4e0b\uff1b<br \/>\n[java]<br \/>\nprivate void copyAssets(Context context) {<br \/>\n\tLog.d(TAG, &quot;Do copyAssets&quot;);<br \/>\n\tAssetManager assetManager = context.getAssets();<br \/>\n\tString[] files = null;<br \/>\n\ttry {<br \/>\n\t\tfiles = assetManager.list(&quot;&quot;);<br \/>\n\t} catch (IOException e) {<br \/>\n\t\tLog.e(TAG, &quot;Failed to get asset file list.&quot;, e);<br \/>\n\t}<br \/>\n\tif (files != null) for (String filename : files) {<br \/>\n\t\tInputStream in = null;<br \/>\n\t\tOutputStream out = null;<br \/>\n\t\ttry {<br \/>\n\t\t\tLog.d(TAG, &quot;Copy &quot; + filename + &quot;&#8230;&#8230;&quot;);<br \/>\n\t\t\tin = assetManager.open(filename);<br \/>\n\t\t\t\/\/File outFile = new File(context.getExternalFilesDir(null), filename);<br \/>\n\t\t\t\/\/File outFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + &quot;\/&quot;, filename);<br \/>\n\t\t\tFile outFile = new File(context.getFilesDir(), filename);<br \/>\n\t\t\tLog.d(TAG, &quot;outFile:&quot; + outFile);<br \/>\n\t\t\tout = new FileOutputStream(outFile);<br \/>\n\t\t\tcopyFile(in, out);<br \/>\n\t\t} catch(IOException e) {<br \/>\n\t\t\tLog.e(TAG, &quot;Failed to copy asset file: &quot; + filename, e);<br \/>\n\t\t}<br \/>\n\t\tfinally {<br \/>\n\t\t\tif (in != null) {<br \/>\n\t\t\t\ttry {<br \/>\n\t\t\t\t\tin.close();<br \/>\n\t\t\t\t} catch (IOException e) {<br \/>\n\t\t\t\t\t\/\/ NOOP<br \/>\n\t\t\t\t}<br \/>\n\t\t\t}<br \/>\n\t\t\tif (out != null) {<br \/>\n\t\t\t\ttry {<br \/>\n\t\t\t\t\tout.close();<br \/>\n\t\t\t\t} catch (IOException e) {<br \/>\n\t\t\t\t\t\/\/ NOOP<br \/>\n\t\t\t\t}<br \/>\n\t\t\t}<br \/>\n\t\t}<br \/>\n\t}<br \/>\n\tLog.d(TAG, &quot;Finished copyAssets&quot;);<br \/>\n}<\/p>\n<p>private void copyFile(InputStream in, OutputStream out) throws IOException {<br \/>\n\tbyte[] buffer = new byte[1024];<br \/>\n\tint read;<br \/>\n\twhile((read = in.read(buffer)) != -1){<br \/>\n\t\tout.write(buffer, 0, read);<br \/>\n\t}<br \/>\n}<br \/>\n[\/java]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u7576\u521d\u70ba\u4e86\u9054\u5230\u81ea\u52d5\u5b89\u88ddAPK\uff0c\u800c\u4e0d\u6703\u8df3\u51fa\u4efb\u4f55\u8a0a\u606f\uff0c\u4e14\u53c8\u4e0d\u80fd\u4f7f\u7528\u975e\u6cd5\u7684API\u6216Java Reflection\u3002 \u7814<span class=\"post-excerpt-end\">&hellip;<\/span><\/p>\n<p class=\"more-link\"><a href=\"https:\/\/learn-house.idv.tw\/?p=2911\" class=\"themebutton\">Read More<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-2911","post","type-post","status-publish","format-standard","hentry","category-5"],"_links":{"self":[{"href":"https:\/\/learn-house.idv.tw\/index.php?rest_route=\/wp\/v2\/posts\/2911","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/learn-house.idv.tw\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/learn-house.idv.tw\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/learn-house.idv.tw\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/learn-house.idv.tw\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2911"}],"version-history":[{"count":0,"href":"https:\/\/learn-house.idv.tw\/index.php?rest_route=\/wp\/v2\/posts\/2911\/revisions"}],"wp:attachment":[{"href":"https:\/\/learn-house.idv.tw\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2911"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/learn-house.idv.tw\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2911"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/learn-house.idv.tw\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2911"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}