Android版本更新完成自动安装解决方案(兼容版本7.0,8.0)

1.简介

  • 发布新版本时,用户已经安装的旧版本提示安装更新
  • 版本更新分为选择更新和强制更新,区别就是弹窗提示是否可以取消,页面是否可以跳转问题

2.特点

1.Android7.0版本以下

这里不做解释,后面看代码。

2.Android7.0版本的FileProvider

主要就是在代码中和AndroidManifest.xml中使用FileProvider类

2.Android8.0及以上版本

版本更新后不能够自动打开安装页面,无法自动安装问题。主要是REQUEST_INSTALL_PACKAGES权限相关的问题

3.代码

  • 主要类DownloadService.java
public class DownloadService extends Service {

    public String DOWNLOAD_PATH = Environment.getExternalStorageDirectory() + "/download/AppUpdate.apk";
    private String url;//下载链接
    private long refernece;

    private BroadcastReceiver receiver;
    private IntentFilter filter;

    public IBinder onBind(Intent arg0) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (intent != null) {
            url = intent.getStringExtra("url");
            if (url != null && !TextUtils.isEmpty(url)) {
                download(url);
            }
        }
        return super.onStartCommand(intent, flags, startId);
    }

    public void download(String url) {
        if (new File(DOWNLOAD_PATH).exists()) {
            new File(DOWNLOAD_PATH).delete();
        }
        receiver();
        DownloadManager dManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
        Uri uri = Uri.parse(url);
        DownloadManager.Request request = new DownloadManager.Request(uri);
        //这里的"AppUpdate.apk"要对应DOWNLOAD_PATH的"AppUpdate.apk"
        request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "AppUpdate.apk");
        request.setDescription("新版本下载中...");
        request.setTitle("版本更新");
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        request.setMimeType("application/vnd.android.package-archive");
        // 设置为可被媒体扫描器找到
        request.allowScanningByMediaScanner();
        // 设置为可见和可管理
        request.setVisibleInDownloadsUi(true);
        try {
            refernece = dManager.enqueue(request);
        } catch (Exception e) {
        }
    }

    public void receiver() {
        filter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
        receiver = new BroadcastReceiver() {
            public void onReceive(Context context, Intent intent) {
                long myDwonloadID = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
                if (refernece == myDwonloadID) {
                    DownloadManager dManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
                    setPermission(DOWNLOAD_PATH);
                    Intent install = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS, Uri.parse("package:" + getPackageName()));
                    install.setAction(Intent.ACTION_VIEW);
                    install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    install.addCategory(Intent.CATEGORY_DEFAULT);
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//大于Android版本7.0
                        //这里的"com.android.app.appupdate.provider"需要和AndroidManifest.xml的provider节点下的authorities属性保持一致
                        Uri contentUri = FileProvider.getUriForFile(context, "com.android.app.appupdate.provider", new File(DOWNLOAD_PATH));
                        install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//这里不能是setFlags(),set会覆盖掉之前的flags
                        install.setDataAndType(contentUri, "application/vnd.android.package-archive");
                    } else {
                        try {
                            Uri downloadFileUri = dManager.getUriForDownloadedFile(refernece);
                            install.setDataAndType(downloadFileUri, "application/vnd.android.package-archive");
                        } catch (RuntimeException e) {
                            e.printStackTrace();
                        }
                    }
                    context.startActivity(install);
                }
            }
        };
        registerReceiver(receiver, filter);
    }

    /**
     * 提升读写权限
     *
     * @param filePath 文件路径
     */
    public static void setPermission(String filePath) {
        String command = "chmod " + "777" + " " + filePath;
        Runtime runtime = Runtime.getRuntime();
        try {
            runtime.exec(command);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void onDestroy() {
        unregisterReceiver(receiver);
    }
}
  • AndroidManifest.xml



    
    
    
    
    
    

    
        
            
                

                
            
        

        

        
        
            
        

    


  • 在res目录下新建xml包,里面创建provider_paths.xml,内容如下:


    
    
    
    

    
    
    
    
    



    


activity做跳转

 Intent intent = new Intent(mActivity, DownloadService.class);
 intent.putExtra("url", "https://github.com/fanhenghao/AppUpdate/raw/master/AppUpdate_release1.0.1.apk");
                                mActivity.startService(intent);

4.参考

  • 我个人GitHub的完整代码示例:AppUpdate

5.总结

  • Android7.0需要FileProvider
  • Android8.0需要一个允许安装未知应用的权限和修改provider_paths.xml的配置路径
  • 可能会遇到下载安装时签名不一致的问题,可以在app下的build.gradle的android节点下添加
signingConfigs {
//这里是你自己的签名相关配置
        release {
            keyAlias 'paymentbox'
            keyPassword 'android'
            storeFile file('/Users/fanhenghao/Desktop/work/paymentbox/paymentbox.jks')
            storePassword 'android'
        }
        debug {
            keyAlias 'paymentbox'
            keyPassword 'android'
            storeFile file('/Users/fanhenghao/Desktop/work/paymentbox/paymentbox.jks')
            storePassword 'android'
        }
 }
  • 我遇到的问题:

1.强制或是选择更新都差不多,就是一个弹窗是否消失和页面是否跳转问题;另外,版本更新一定需要存储权限,如果app涉及到强制更新的话,我做的是不给存储权限直接退出app。
2.先前以为8.0系统的手机需要用户手动给予安装未知应用的权限,结果小米平台的审核不通过,所以做了不需要强制用户打开的安装未知应用的权限。

你可能感兴趣的:(android)