PackageManagerCompat.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. package com.emato.ich.update;
  2. import android.app.Activity;
  3. import android.app.AlarmManager;
  4. import android.app.PendingIntent;
  5. import android.content.Context;
  6. import android.content.Intent;
  7. import android.content.pm.PackageInstaller;
  8. import android.content.pm.PackageManager;
  9. import android.net.Uri;
  10. import android.os.Build;
  11. import android.os.storage.StorageManager;
  12. import android.os.storage.StorageVolume;
  13. import com.emato.ich.utils.Log;
  14. import androidx.annotation.NonNull;
  15. import androidx.annotation.RequiresApi;
  16. import com.emato.ich.MainActivity;
  17. import com.emato.ich.utils.LoggingUtils;
  18. import com.emato.ich.utils.StringUtils;
  19. import com.emato.ich.utils.ToastUtils;
  20. import com.xuexiang.xupdate.entity.DownloadEntity;
  21. import com.xuexiang.xupdate.listener.OnInstallListener;
  22. import org.jetbrains.annotations.NotNull;
  23. import java.io.BufferedReader;
  24. import java.io.Closeable;
  25. import java.io.DataOutputStream;
  26. import java.io.File;
  27. import java.io.FileInputStream;
  28. import java.io.IOException;
  29. import java.io.InputStream;
  30. import java.io.InputStreamReader;
  31. import java.io.OutputStream;
  32. import java.lang.reflect.Array;
  33. import java.lang.reflect.InvocationTargetException;
  34. import java.lang.reflect.Method;
  35. import java.text.DateFormat;
  36. import java.text.SimpleDateFormat;
  37. import java.util.Date;
  38. import java.util.concurrent.atomic.AtomicBoolean;
  39. /**
  40. * 自定义的安装类
  41. */
  42. public class PackageManagerCompat implements OnInstallListener {
  43. private static final String TAG = PackageManagerCompat.class.getName();
  44. /*public static void install(Activity activity, File apkFile, OnInstallListener listener){
  45. try{
  46. Intent intent =new Intent();
  47. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  48. //Uri uri = Uri.fromFile(apkFile);
  49. Uri uri = null;
  50. //todo N FileProvider
  51. //todo O install permission
  52. if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
  53. uri = androidx.core.content.FileProvider.getUriForFile(activity,activity.getPackageName()+".fileprovider", apkFile);
  54. intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
  55. intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
  56. }else{
  57. uri = Uri.fromFile(apkFile);
  58. }
  59. intent.setDataAndType(uri, "application/vnd.android.package-archive");
  60. activity.startActivity(intent);
  61. listener.onInstallSuccess();
  62. } catch (Exception e) {
  63. listener.onInstallException(e);
  64. }
  65. }*/
  66. /**
  67. * android 9.0获取外置sdcard和U盘路径,并区分
  68. * @param mContext 上下文
  69. * SD = "内部存储"; EXT = "SD卡"; USB = "U盘"
  70. * @return apk
  71. */
  72. public static File getUpdateAPKFile(Context mContext){
  73. String targetpath = "";
  74. String keyword = "USB";
  75. StorageManager mStorageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
  76. Class<?> storageVolumeClazz = null;
  77. File file = null;
  78. try {
  79. storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");
  80. Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList");
  81. Method getPath = storageVolumeClazz.getMethod("getPath");
  82. Object result = getVolumeList.invoke(mStorageManager);
  83. final int length = Array.getLength(result);
  84. Method getUserLabel = storageVolumeClazz.getMethod("getUserLabel");
  85. for (int i = 0; i < length; i++){
  86. StorageVolume storageVolumeElement = (StorageVolume) Array.get(result, i);
  87. String userLabel = (String) getUserLabel.invoke(storageVolumeElement);
  88. String path = (String) getPath.invoke(storageVolumeElement);
  89. if(!userLabel.contains("内部存储") && !storageVolumeElement.isEmulated()){
  90. targetpath = path;
  91. targetpath = targetpath +"/app-release.apk";
  92. file = new File(targetpath);
  93. if (!file.exists()) {
  94. ToastUtils.make(mContext, "U盘根目录下不存在升级所需APK!请检查APK存放目录!");
  95. return file;
  96. }
  97. }
  98. }
  99. } catch (ClassNotFoundException e){
  100. Log.e(TAG, "类找不到异常", e);
  101. LoggingUtils.sendAppErrorLog("类找不到异常", e);
  102. } catch (InvocationTargetException e) {
  103. Log.e(TAG, "反射调用目标方法异常", e);
  104. LoggingUtils.sendAppErrorLog("反射调用目标方法异常", e);
  105. } catch (NoSuchMethodException e) {
  106. Log.e(TAG, "反射找不到目标方法", e);
  107. LoggingUtils.sendAppErrorLog("反射找不到目标方法", e);
  108. } catch (IllegalAccessException e) {
  109. Log.e(TAG, "没有权限", e);
  110. LoggingUtils.sendAppErrorLog("没有权限", e);
  111. }
  112. return file;
  113. }
  114. @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
  115. public static void install(Context context, String apkFilePath, PackageManager packageManager, InstallListener listener) {
  116. try {
  117. Log.i(TAG, "install: 应用程序开始安装! " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
  118. File apkFile = new File(apkFilePath);
  119. if (!apkFile.exists()) {
  120. throw new RuntimeException("文件不存在! 更新失败! ");
  121. }
  122. PackageInstaller packageInstaller = packageManager.getPackageInstaller();
  123. PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);
  124. sessionParams.setSize(apkFile.length());
  125. int sessionId = createSession(packageInstaller, sessionParams);
  126. if (sessionId != -1) {
  127. boolean copySuccess = copyInstallFile(packageInstaller, sessionId, apkFilePath, listener);
  128. if (copySuccess) {
  129. execInstallCommand(context, packageInstaller, sessionId, listener);
  130. }
  131. }
  132. Log.i(TAG, "install: 应用程序安装完成! " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
  133. } catch (Exception e) {
  134. listener.onInstallException(e);
  135. }
  136. }
  137. @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
  138. private static int createSession(PackageInstaller packageInstaller,
  139. PackageInstaller.SessionParams sessionParams) {
  140. int sessionId = -1;
  141. try {
  142. sessionId = packageInstaller.createSession(sessionParams);
  143. } catch (IOException e) {
  144. e.printStackTrace();
  145. }
  146. return sessionId;
  147. }
  148. @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
  149. private static boolean copyInstallFile(PackageInstaller packageInstaller,
  150. int sessionId, String apkFilePath, InstallListener listener) {
  151. InputStream in = null;
  152. OutputStream out = null;
  153. PackageInstaller.Session session = null;
  154. boolean success = false;
  155. try {
  156. File apkFile = new File(apkFilePath);
  157. session = packageInstaller.openSession(sessionId);
  158. out = session.openWrite("base.apk", 0, apkFile.length());
  159. in = new FileInputStream(apkFile);
  160. int total = 0, c;
  161. byte[] buffer = new byte[65536];
  162. while ((c = in.read(buffer)) != -1) {
  163. total += c;
  164. out.write(buffer, 0, c);
  165. }
  166. session.fsync(out);
  167. success = true;
  168. } catch (IOException e) {
  169. listener.onInstallException(e);
  170. } finally {
  171. closeQuietly(out, listener);
  172. closeQuietly(in, listener);
  173. closeQuietly(session, listener);
  174. }
  175. return success;
  176. }
  177. @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
  178. private static void execInstallCommand(Context context, PackageInstaller packageInstaller, int sessionId, InstallListener listener) {
  179. PackageInstaller.Session session = null;
  180. try {
  181. session = packageInstaller.openSession(sessionId);
  182. Intent intent = new Intent(context, InstallResultReceiver.class);
  183. PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
  184. session.commit(pendingIntent.getIntentSender());
  185. listener.onInstallSuccess();
  186. } catch (IOException e) {
  187. listener.onInstallException(e);
  188. } finally {
  189. closeQuietly(session, listener);
  190. }
  191. }
  192. private static void closeQuietly(Closeable c, InstallListener listener) {
  193. if (c != null) {
  194. try {
  195. c.close();
  196. } catch (IOException ignored) {
  197. listener.onInstallException(ignored);
  198. }
  199. }
  200. }
  201. /**
  202. * 重启
  203. * @param context 应用上下文
  204. */
  205. public static void restartApp(Context context) {
  206. Log.i(TAG, "restartApp: 应用程序重启中! 日期=====>" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
  207. try {
  208. Intent intent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
  209. if (intent != null && !StringUtils.isNullOrEmpty(intent.getAction()) && intent.getAction().equals("android.intent.action.PACKAGE_REPLACED")) {
  210. Intent intent1 = new Intent(context, MainActivity.class);
  211. intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  212. context.startActivity(intent1);
  213. Log.i(TAG, "restartApp: ======================================>重启成功");
  214. }
  215. } catch (Exception e) {
  216. Log.e(TAG, "restartApp: ======================================>重启失败! ", e);
  217. LoggingUtils.sendErrorLog("业务异常: ======================================>重启失败! ", e);
  218. }
  219. // PendingIntent restartIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_ONE_SHOT);
  220. // AlarmManager mgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
  221. // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {// 6.0及以上
  222. // mgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 10000, restartIntent);
  223. //
  224. // } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {// 4.4及以上
  225. // mgr.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 10000, restartIntent);
  226. // }
  227. Log.i(TAG, "restartApp: 应用程序重启完成! 日期=====>" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
  228. }
  229. @Override
  230. public boolean onInstallApk(@NonNull @NotNull Context context, @NonNull @NotNull File apkFile, @NonNull @NotNull DownloadEntity downloadEntity) {
  231. AtomicBoolean flag = new AtomicBoolean(true);
  232. install(context, apkFile.getAbsolutePath(), context.getPackageManager(), new InstallListener(){
  233. @Override
  234. public void onInstallException(Exception e) {
  235. Log.e(TAG, "onInstallException: 安装失败! ", e);
  236. flag.set(false);
  237. }
  238. @Override
  239. public void onInstallSuccess() {
  240. restartApp(context);
  241. }
  242. });
  243. return flag.get();
  244. }
  245. @Override
  246. public void onInstallApkSuccess() {
  247. Log.i(TAG, "onInstallApkSuccess: 安装成功! ");
  248. }
  249. }