当前位置:   article > 正文

Android 7.1 修改源码实现app的静默安装 & 安装完成之后自动打开安装的应用._android7.1 修改源码实现app的

android7.1 修改源码实现app的

真正的静默安装是不需要用户进行任何点击操作的,目前大部分博客所说的静默安装还是需要弹出确认界面,让用户点击授权安装,我认为真正的静默安装应该是不需要用户任何确定操作,就比如现在的好多应用市场安装软件才是真正的静默安装.

目前公司也想要实现和应用市场类似的安装方式,我们不难发现 像小米和华为 google都有个人的应用市场,而这写应用市场的app并不互通,比如我将小米应用市场app安装到华为手机上面就不能像小米手机里的自带的应用市场那样实现静默安装.

为了不影响正常的权限检查,我们需要对系统源码就行修改,自己添加了一安装的接口

 

具体修改如下:

修改packages/apps/PackageInstaller/AndroidManifest.xml

增加如下权限

<uses-permission android:name="android.permission.MANAGE_DOCUMENT" />

 

创建如下 receiver 

  1. <receiver android:name=".SilentInstallerReceiver" android:exported="true" >
  2. <intent-filter>
  3. <action android:name="xxx.intent.action.SILENT.INSTALLER" ></action>
  4. <action android:name="xxx.intent.action.SILENT.INSTALLER.COMMIT"></action>
  5. </intent-filter>
  6. </receiver>

增加如下文件 packages/apps/PackageInstaller/src/com/android/packageinstaller/SilentInstallerReceiver.java

  1. package com.android.packageinstaller;
  2. import android.app.PendingIntent;
  3. import android.content.BroadcastReceiver;
  4. import android.content.Context;
  5. import android.content.Intent;
  6. import android.content.pm.PackageInfo;
  7. import android.content.pm.PackageInstaller;
  8. import android.content.pm.PackageManager;
  9. import android.content.pm.PackageParser;
  10. import android.content.pm.PackageUserState;
  11. import android.net.Uri;
  12. import android.os.AsyncTask;
  13. import android.os.Handler;
  14. import android.os.HandlerThread;
  15. import android.text.TextUtils;
  16. import android.util.Log;
  17. import com.android.internal.content.PackageHelper;
  18. import com.android.packageinstaller.permission.utils.IoUtils;
  19. import java.io.File;
  20. import java.io.FileInputStream;
  21. import java.io.FileOutputStream;
  22. import java.io.IOException;
  23. import java.io.InputStream;
  24. import java.io.OutputStream;
  25. public class SilentInstallerReceiver extends BroadcastReceiver {
  26. private static final String TAG = "SilentInstallerReceiver";
  27. private static final String BROADCAST_ACTION = "xxx.intent.action.SILENT.INSTALLER.COMMIT";
  28. private static final String PACKAGENAME = "slient_name";
  29. private static final String INSTLLPATH = "instll_path";
  30. private static final String SCHEME_FILE = "file";
  31. private static final String SCHEME_CONTENT = "content";
  32. private static final String SCHEME_PACKAGE = "package";
  33. private Context mContext;
  34. private Uri mPackageURI;
  35. private Intent mLaunchIntent;
  36. private HandlerThread mInstallThread;
  37. private Handler mInstallHandler;
  38. private AsyncTask<Uri, Void, File> mStagingAsynTask;
  39. private PackageManager mPm;
  40. private PackageInfo mPkgInfo;
  41. @Override
  42. public void onReceive(Context context, Intent intent) {
  43. mContext = context;
  44. boolean wasSetUp = false;
  45. mInstallThread = new HandlerThread("InstallThread");
  46. mInstallThread.start();
  47. mInstallHandler = new Handler(mInstallThread.getLooper());
  48. mPm = context.getPackageManager();
  49. String instllpath = intent.getStringExtra(INSTLLPATH);
  50. // TODO this is lunch APP
  51. if (!BROADCAST_ACTION.equals(intent.getAction())) {
  52. if (TextUtils.isEmpty(instllpath)) {
  53. return;
  54. }
  55. mPackageURI = Uri.parse(instllpath);
  56. if (mPackageURI.getScheme() == null) {
  57. instllpath = "file://" + instllpath;
  58. mPackageURI = Uri.parse(instllpath);
  59. }
  60. Log.d(TAG, " mPackageURI = " + mPackageURI + " , intent getAction = " + intent.getAction());
  61. wasSetUp = processPackageUri(mPackageURI);
  62. }
  63. if (BROADCAST_ACTION.equals(intent.getAction())) {
  64. Log.d(TAG, " install app , so return !!! ");
  65. onPackageInstalled(intent);
  66. return;
  67. }
  68. if (mPackageURI == null) {
  69. Log.d(TAG, " mPackageURI is null , so return !!! ");
  70. return;
  71. }
  72. if (!wasSetUp) {
  73. Log.d(TAG, " wasSetUp is false, return!!! ");
  74. return;
  75. }
  76. initiateInstall();
  77. }
  78. private void initiateInstall() {
  79. String pkgName = mPkgInfo.packageName;
  80. // Check if there is already a package on the device with this name
  81. // but it has been renamed to something else.
  82. String[] oldName = mPm.canonicalToCurrentPackageNames(new String[]{pkgName});
  83. if (oldName != null && oldName.length > 0 && oldName[0] != null) {
  84. pkgName = oldName[0];
  85. mPkgInfo.packageName = pkgName;
  86. mPkgInfo.applicationInfo.packageName = pkgName;
  87. }
  88. Log.d(TAG, " cdownloaded app uri= " + mPackageURI);
  89. startSilentInstaller();
  90. }
  91. int getInstallFlags(String packageName) {
  92. PackageManager pm = mContext.getPackageManager();
  93. try {
  94. PackageInfo pi =
  95. pm.getPackageInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
  96. if (pi != null) {
  97. return PackageManager.INSTALL_REPLACE_EXISTING;
  98. }
  99. } catch (PackageManager.NameNotFoundException e) {
  100. }
  101. return 0;
  102. }
  103. void startSilentInstaller() {
  104. final PackageManager pm = mContext.getPackageManager();
  105. final int installFlags = getInstallFlags(mPkgInfo.applicationInfo.packageName);
  106. if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
  107. Log.w(TAG, "Replacing package:" + mPkgInfo.applicationInfo.packageName);
  108. }
  109. Log.d(TAG, " starSilentInstaller + packageName " + mPkgInfo.applicationInfo.packageName);
  110. final PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
  111. PackageInstaller.SessionParams.MODE_FULL_INSTALL);
  112. File file = new File(mPackageURI.getPath());
  113. try {
  114. PackageParser.PackageLite pkg = PackageParser.parsePackageLite(file, 0);
  115. params.setAppPackageName(pkg.packageName);
  116. params.setInstallLocation(pkg.installLocation);
  117. params.setSize(
  118. PackageHelper.calculateInstalledSize(pkg, false, params.abiOverride));
  119. } catch (PackageParser.PackageParserException e) {
  120. Log.e(TAG, "Cannot parse package " + file + ". Assuming defaults.");
  121. Log.e(TAG, "Cannot calculate installed size " + file + ". Try only apk size.");
  122. params.setSize(file.length());
  123. } catch (IOException e) {
  124. Log.e(TAG, "Cannot calculate installed size " + file + ". Try only apk size.");
  125. params.setSize(file.length());
  126. }
  127. mInstallHandler.post(new Runnable() {
  128. @Override
  129. public void run() {
  130. doPackageStage(pm, params);
  131. }
  132. });
  133. }
  134. private void doPackageStage(PackageManager pm, PackageInstaller.SessionParams params) {
  135. final PackageInstaller packageInstaller = pm.getPackageInstaller();
  136. PackageInstaller.Session session = null;
  137. try {
  138. final String packageLocation = mPackageURI.getPath();
  139. final File file = new File(packageLocation);
  140. final int sessionId = packageInstaller.createSession(params);
  141. final byte[] buffer = new byte[65536];
  142. session = packageInstaller.openSession(sessionId);
  143. final InputStream in = new FileInputStream(file);
  144. final long sizeBytes = file.length();
  145. final OutputStream out = session.openWrite("PackageInstaller", 0, sizeBytes);
  146. try {
  147. int c;
  148. while ((c = in.read(buffer)) != -1) {
  149. out.write(buffer, 0, c);
  150. if (sizeBytes > 0) {
  151. final float fraction = ((float) c / (float) sizeBytes);
  152. session.addProgress(fraction);
  153. }
  154. }
  155. session.fsync(out);
  156. } finally {
  157. IoUtils.closeQuietly(in);
  158. IoUtils.closeQuietly(out);
  159. }
  160. // TODO this is lunch APP Broast
  161. // Create a PendingIntent and use it to generate the IntentSender
  162. Intent broadcastIntent = new Intent(BROADCAST_ACTION);
  163. broadcastIntent.putExtra(PACKAGENAME, mPkgInfo.applicationInfo.packageName);
  164. PendingIntent pendingIntent = PendingIntent.getBroadcast(
  165. mContext /*context*/,
  166. sessionId,
  167. broadcastIntent,
  168. PendingIntent.FLAG_UPDATE_CURRENT);
  169. session.commit(pendingIntent.getIntentSender());
  170. } catch (IOException e) {
  171. } finally {
  172. IoUtils.closeQuietly(session);
  173. }
  174. }
  175. /**
  176. * TODO this is lunch APP Receiver Broast
  177. * after app installed ,open the install app
  178. *
  179. * @param intent get insalled app name {@param BROADCAST_ACTION}
  180. */
  181. void onPackageInstalled(Intent intent) {
  182. Log.d(TAG, " install app is finishing, start luncher install app");
  183. mLaunchIntent = mContext.getPackageManager().getLaunchIntentForPackage(
  184. intent.getStringExtra(PACKAGENAME));
  185. if (mLaunchIntent == null) return;
  186. mLaunchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  187. mContext.startActivity(mLaunchIntent);
  188. }
  189. /**
  190. * delete the apk
  191. */
  192. private void clearCachedApkIfNeededAndFinish() {
  193. if ("file".equals(mPackageURI.getScheme()) && mPackageURI.getPath() != null
  194. && mPackageURI.getPath().startsWith(mContext.getCacheDir().toString())) {
  195. File file = new File(mPackageURI.getPath());
  196. file.delete();
  197. }
  198. }
  199. /**
  200. * Parse the Uri and set up the installer for this package.
  201. *
  202. * @param packageUri The URI to parse
  203. * @return {@code true} iff the installer could be set up
  204. */
  205. private boolean processPackageUri(final Uri packageUri) {
  206. mPackageURI = packageUri;
  207. final String scheme = packageUri.getScheme();
  208. Log.d(TAG, " scheme = " + scheme + " packageUri " + packageUri);
  209. switch (scheme) {
  210. case SCHEME_PACKAGE: {
  211. try {
  212. mPkgInfo = mPm.getPackageInfo(packageUri.getSchemeSpecificPart(),
  213. PackageManager.GET_PERMISSIONS
  214. | PackageManager.GET_UNINSTALLED_PACKAGES);
  215. } catch (PackageManager.NameNotFoundException e) {
  216. }
  217. if (mPkgInfo == null) {
  218. Log.w(TAG, "Requested package " + packageUri.getScheme()
  219. + " not available. Discontinuing installation");
  220. return false;
  221. }
  222. }
  223. break;
  224. case SCHEME_FILE: {
  225. File sourceFile = new File(packageUri.getPath());
  226. PackageParser.Package parsed = PackageUtil.getPackageInfo(sourceFile);
  227. // Check for parse errors
  228. if (parsed == null) {
  229. Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation");
  230. return false;
  231. }
  232. mPkgInfo = PackageParser.generatePackageInfo(parsed, null,
  233. PackageManager.GET_PERMISSIONS, 0, 0, null,
  234. new PackageUserState());
  235. }
  236. break;
  237. case SCHEME_CONTENT: {
  238. mStagingAsynTask = new SilentInstallerReceiver.StagingAsyncTask();
  239. mStagingAsynTask.execute(packageUri);
  240. return false;
  241. }
  242. default: {
  243. Log.w(TAG, "Unsupported scheme " + scheme);
  244. clearCachedApkIfNeededAndFinish();
  245. return false;
  246. }
  247. }
  248. return true;
  249. }
  250. private final class StagingAsyncTask extends AsyncTask<Uri, Void, File> {
  251. @Override
  252. protected void onPreExecute() {
  253. // TODO nothing to do
  254. }
  255. @Override
  256. protected File doInBackground(Uri... params) {
  257. if (params == null || params.length <= 0) {
  258. return null;
  259. }
  260. Uri packageUri = params[0];
  261. File sourceFile = null;
  262. try {
  263. sourceFile = File.createTempFile("package", ".apk", mContext.getApplicationContext().getCacheDir());
  264. try (
  265. InputStream in = mContext.getApplicationContext().getContentResolver().openInputStream(packageUri);
  266. OutputStream out = (in != null) ? new FileOutputStream(
  267. sourceFile) : null;
  268. ) {
  269. // Despite the comments in ContentResolver#openInputStream
  270. // the returned stream can be null.
  271. if (in == null) {
  272. return null;
  273. }
  274. byte[] buffer = new byte[4096];
  275. int bytesRead;
  276. while ((bytesRead = in.read(buffer)) >= 0) {
  277. // Be nice and respond to a cancellation
  278. if (isCancelled()) {
  279. return null;
  280. }
  281. out.write(buffer, 0, bytesRead);
  282. }
  283. }
  284. } catch (IOException ioe) {
  285. Log.w(TAG, "Error staging apk from content URI", ioe);
  286. if (sourceFile != null) {
  287. sourceFile.delete();
  288. }
  289. }
  290. return sourceFile;
  291. }
  292. @Override
  293. protected void onPostExecute(File file) {
  294. if (file == null) {
  295. return;
  296. }
  297. Uri fileUri = Uri.fromFile(file);
  298. boolean wasSetUp = processPackageUri(fileUri);
  299. if (wasSetUp) {
  300. initiateInstall();
  301. }
  302. }
  303. @Override
  304. protected void onCancelled(File file) {
  305. // TODO nothing to do
  306. }
  307. }
  308. }

创建完成之后重新编译 PackageInstaller apk push到手机里面重启手机.

使用adb发送广播进行静默安装操作验证,当下载好文件后下,下发如下操作即可.

adb shell am broadcast -a xxx.intent.action.SILENT.INSTALLER --es instllpath "apk路径"

执行此命令许等待 5-10秒钟,等待的时间和手机的性能有关系,性能越好等待越短.安装完成之后直接将apk拉起,不需要任何操作,

如果不想安装完成之后被拉起来将如下代码注注释掉即可.

<action android:name="xxx.intent.action.SILENT.INSTALLER.COMMIT"></action>

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/236562
推荐阅读
相关标签
  

闽ICP备14008679号