android app版本升级(DownloadManager、适配6.0、7.0)

来源:互联网 发布:c语言99个例题 编辑:程序博客网 时间:2024/06/05 09:32

说明:

1.本文使用系统DownloadManager在通知栏更新下载进度
2.动态权限使用第三方库EasyPermissions(https://github.com/googlesamples/easypermissions)
3.下载完成的App安装适配7.0
4.提示下载框(AlertDialog)是依附于Activity(UpdateActivity)的,这样做是为了解决“进入首页后,开启自动检测升级,检测到有升级的版本就随时弹框提示用户,但此时用户可能已经在操作APP进入其他页面,怎么保证弹框可以正常弹出?”这一问题并适配各大机型

升级流程图

这里写图片描述

MianActivity源码

public class MainActivity extends BaseActivity        implements EasyPermissions.PermissionCallbacks, CheckUpdateManager.RequestPermissions {//...    private Version mVersion;//版本控制bean    private static final int RC_EXTERNAL_STORAGE = 0x04;//存储权限//...    //BaseActivity方法,返回布局文件    @Override    protected int getContentView() {        return R.layout.activity_main_ui;    }     //BaseActivity方法,初始化data    @Override    protected void initData() {        super.initData();        // 检查版本升级        checkUpdate();    }    //CheckUpdateManager回调接口 CheckUpdateManager封装了网络请求     @Override    public void call(Version version) {        this.mVersion = version;        requestExternalStorage();}    @AfterPermissionGranted(RC_EXTERNAL_STORAGE)    public void requestExternalStorage() {        if (EasyPermissions.hasPermissions(this, Manifest.permission.READ_EXTERNAL_STORAGE)) {            DownloadService.startService(this, mVersion.getDownloadUrl());        } else {            EasyPermissions.requestPermissions(this, "", RC_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE);        }    }    @Override    public void onPermissionsGranted(int requestCode, List<String> perms) {    }    @Override    public void onPermissionsDenied(int requestCode, List<String> perms) {        for (String perm : perms) {            if (perm.equals(Manifest.permission.READ_EXTERNAL_STORAGE)) {                //DialogHelper:Alerdialog分装类                DialogHelper.getConfirmDialog(this, "温馨提示", "需要开启您手机的存储权限才能下载安装,是否现在开启", "去开启", "取消", true, new DialogInterface.OnClickListener() {                    @Override                    public void onClick(DialogInterface dialog, int which) {                        startActivity(new Intent(Settings.ACTION_APPLICATION_SETTINGS));                    }                }, null).show();            } else {            //SharedPreferences中保存授权状态                Setting.updateLocationPermission(getApplicationContext(), false);            }        }    }    @Override    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);    }    private void checkUpdate() {            CheckUpdateManager manager = new         manager.checkUpdate();    }}

CheckUpdateManager 源码

public class CheckUpdateManager {    private ProgressDialog mWaitDialog;    private Context mContext;    private boolean mIsShowDialog;    public CheckUpdateManager(Context context, boolean showWaitingDialog) {        this.mContext = context;        mIsShowDialog = showWaitingDialog;        if (mIsShowDialog) {            mWaitDialog = DialogHelper.getProgressDialog(mContext);            mWaitDialog.setMessage("正在检查中...");            mWaitDialog.setCancelable(false);            mWaitDialog.setCanceledOnTouchOutside(false);        }    }    public void checkUpdate() {        if (mIsShowDialog) {            mWaitDialog.show();        }        OSChinaApi.checkUpdate(new TextHttpResponseHandler() {            @Override            public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {                if (mIsShowDialog) {                    DialogHelper.getMessageDialog(mContext, "网络异常,无法获取新版本信息").show();                }            }            @Override            public void onSuccess(int statusCode, Header[] headers, String responseString) {                        //此处省略若干代码                            int curVersionCode = TDevice.getVersionCode(AppContext                                    .getInstance().getPackageName());                                    //version:服务器解析后实体bean                            if (curVersionCode < version.getCode()) {                                UpdateActivity.show((Activity) mContext, version);                                                         } else {                                if (mIsShowDialog) {                                    DialogHelper.getMessageDialog(mContext, "已经是新版本了").show();                                }                            }                 }            @Override            public void onFinish() {                super.onFinish();                if (mIsShowDialog) {                    mWaitDialog.dismiss();                }            }        });    }}

UpdateActivity源码

public class UpdateActivity extends BaseActivity implements View.OnClickListener,        EasyPermissions.PermissionCallbacks {    @Bind(R.id.tv_update_info)    TextView mTextUpdateInfo;    private Version mVersion;    private static final int RC_EXTERNAL_STORAGE = 0x04;//存储权限    public static void show(Activity activity, Version version) {        Intent intent = new Intent(activity, UpdateActivity.class);        intent.putExtra("version", version);        activity.startActivityForResult(intent, 0x01);    }    @Override    protected int getContentView() {        return R.layout.activity_update;    }    @SuppressWarnings("deprecation")    @Override    protected void initData() {        super.initData();        setTitle("");        getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);        mVersion = (Version) getIntent().getSerializableExtra("version");        mTextUpdateInfo.setText(Html.fromHtml(mVersion.getMessage()));    }    @OnClick({R.id.btn_update, R.id.btn_close})    @Override    public void onClick(View v) {        switch (v.getId()) {            case R.id.btn_update:                if (!TDevice.isWifiOpen()) {                    DialogHelper.getConfirmDialog(this, "当前非wifi环境,是否升级?", new DialogInterface.OnClickListener() {                        @Override                        public void onClick(DialogInterface dialog, int which) {                            requestExternalStorage();                                                }                    }, new DialogInterface.OnClickListener() {                        @Override                        public void onClick(DialogInterface dialog, int which) {                            finish();                        }                    }).show();                } else {                    requestExternalStorage();                }                break;            case R.id.btn_close:                finish();                break;        }    }    @AfterPermissionGranted(RC_EXTERNAL_STORAGE)    public void requestExternalStorage() {        if (EasyPermissions.hasPermissions(this, Manifest.permission.READ_EXTERNAL_STORAGE)) {            AppUpgradeManager.getInstance(this, mVersion).startDown();            finish();        } else {            EasyPermissions.requestPermissions(this, "需要开启对您手机的存储权限才能下载安装", RC_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE);        }    }    @Override    public void onPermissionsGranted(int requestCode, List<String> perms) {    }    @Override    public void onPermissionsDenied(int requestCode, List<String> perms) {    //当权限窗口不能弹出式调用-用户勾选了不再提醒        if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {            DialogHelper.getConfirmDialog(UpdateActivity.this, "温馨提示", "需要开启对您手机的存储权限才能下载安装,是否现在开启", "去开启", "取消", true, new DialogInterface.OnClickListener() {                @Override                public void onClick(DialogInterface dialog, int which) {                    startActivity(new Intent(Settings.ACTION_APPLICATION_SETTINGS));                }            }, new DialogInterface.OnClickListener() {                @Override                public void onClick(DialogInterface dialog, int which) {                    finish();                }            }).show();        } else {            finish();        }    }    @Override    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);    }}

AppUpgradeManager源码

public class AppUpgradeManager {    private volatile static AppUpgradeManager sAppUpgradeManager;    private DownloadManager downloader;    private Context appContext;    private NotificationClickReceiver mNotificationClickReceiver;    private DownloadReceiver mDownloaderReceiver;    private String apkName = AppConfig.APP_NAME;    //apk下载文件的路径    private String downloadApkPath;    //   服务器返回的版本信息    private Version latestVersion;    public AppUpgradeManager(Context context, Version version) {        appContext = context.getApplicationContext();        latestVersion = version;        mDownloaderReceiver = new DownloadReceiver();        mNotificationClickReceiver = new NotificationClickReceiver();    }    public static AppUpgradeManager getInstance(Context context, Version version) {        if (sAppUpgradeManager == null) {            synchronized (AppUpgradeManager.class) {                if (sAppUpgradeManager == null) {                    sAppUpgradeManager = new AppUpgradeManager(context, version);                }            }        }        return sAppUpgradeManager;    }    public void startDown() {        //确定apk下载的绝对路径        String dirPath = AppConfig.DEFAULT_SAVE_FILE_PATH_PUBLIC;        //AppConfig.DEFAULT_SAVE_FILE_PATH_PUBLIC=Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();        dirPath = dirPath.endsWith(File.separator) ? dirPath : dirPath + File.separator;        downloadApkPath = dirPath + apkName;        //先检查本地是否已经有需要升级版本的安装包,如有就不需要再下载        File targetApkFile = new File(downloadApkPath);        if (targetApkFile.exists()) {            PackageManager pm = appContext.getPackageManager();            PackageInfo info = pm.getPackageArchiveInfo(downloadApkPath, PackageManager.GET_ACTIVITIES);            if (info != null) {                String versionCode = String.valueOf(info.versionCode);                //比较已下载到本地的apk安装包,与服务器上apk安装包的版本号是否一致                if (String.valueOf(latestVersion.getCode()).equals(versionCode)) {                    installApk();                    return;                }            }        }        //要检查本地是否有安装包,有则删除重新下        File apkFile = new File(downloadApkPath);        if (apkFile.exists()) {            apkFile.delete();        }        if (downloader == null) {            downloader = (DownloadManager) appContext.getSystemService(Context.DOWNLOAD_SERVICE);        }        //开始下载        DownloadManager.Query query = new DownloadManager.Query();        long downloadTaskId = TDevice.getDownloadTaskId(appContext);        query.setFilterById(downloadTaskId);        Cursor cur = downloader.query(query);        // 检查下载任务是否已经存在        if (cur.moveToFirst()) {            int columnIndex = cur.getColumnIndex(DownloadManager.COLUMN_STATUS);            int status = cur.getInt(columnIndex);            if (DownloadManager.STATUS_PENDING == status || DownloadManager.STATUS_RUNNING == status || DownloadManager.STATUS_PAUSED == status) {                cur.close();                Toast.makeText(appContext, "更新任务已在后台进行中,无需重复更新", Toast.LENGTH_LONG).show();                return;            }        }        cur.close();        DownloadManager.Request task = new DownloadManager.Request(Uri.parse(latestVersion.getDownloadUrl()));        //定制Notification的样式        String title = "最新版本:" + latestVersion.getCode();        task.setTitle(title);        task.setDescription("本次更新:\n1.增强系统稳定性\n2.修复已知bug");        task.setVisibleInDownloadsUi(true);        //设置是否允许手机在漫游状态下下载        //task.setAllowedOverRoaming(false);        //限定在WiFi下进行下载        //task.setAllowedNetworkTypes(Request.NETWORK_WIFI);        task.setMimeType("application/vnd.android.package-archive");        // 在通知栏通知下载中和下载完成        // 下载完成后该Notification才会被显示        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) {            // 3.0(11)以后才有该方法            //在下载过程中通知栏会一直显示该下载的Notification,在下载完成后该Notification会继续显示,直到用户点击该Notification或者消除该Notification            task.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);        }        // 可能无法创建Download文件夹,如无sdcard情况,系统会默认将路径设置为/data/data/com.android.providers.downloads/cache/xxx.apk        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {            task.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, apkName);        }// 自定义文件路径//task.setDestinationUri()        downloadTaskId = downloader.enqueue(task);        //TDevice SharedPreferences封装类        TDevice.saveDownloadTaskId(appContext, downloadTaskId);        //注册下载完成广播        appContext.registerReceiver(mDownloaderReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));        appContext.registerReceiver(mNotificationClickReceiver, new IntentFilter(DownloadManager.ACTION_NOTIFICATION_CLICKED));    }    private void installApk() {        if (TextUtils.isEmpty(downloadApkPath)) {            Toast.makeText(appContext, "APP安装文件不存在或已损坏", Toast.LENGTH_LONG).show();            return;        }        File apkFile = new File(Uri.parse(downloadApkPath).getPath());        if (!apkFile.exists()) {            Toast.makeText(appContext, "APP安装文件不存在或已损坏", Toast.LENGTH_LONG).show();            return;        }        Intent intent = new Intent(Intent.ACTION_VIEW);        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {            intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);            Uri contentUri = FileProvider.getUriForFile(appContext, "net.xxx.app.provider", apkFile);            intent.setDataAndType(contentUri, "application/vnd.android.package-archive");        } else {            intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);        }        appContext.startActivity(intent);    }    /**     * 下载完成的广播     */    class DownloadReceiver extends BroadcastReceiver {        @Override        public void onReceive(Context context, Intent intent) {            if (downloader == null) {                return;            }            long completeId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);            long downloadTaskId = TDevice.getDownloadTaskId(context);            if (completeId != downloadTaskId) {                return;            }            DownloadManager.Query query = new DownloadManager.Query();            query.setFilterById(downloadTaskId);            Cursor cur = downloader.query(query);            if (!cur.moveToFirst()) {                return;            }            int columnIndex = cur.getColumnIndex(DownloadManager.COLUMN_STATUS);            if (DownloadManager.STATUS_SUCCESSFUL == cur.getInt(columnIndex)) {                installApk();            } else {                Toast.makeText(appContext, "下载App最新版本失败!", Toast.LENGTH_LONG).show();            }            // 下载任务已经完成,清除            TDevice.removeDownloadTaskId(context);            cur.close();        }    }    /**     * 点击通知栏下载项目,下载完成前点击都会进来,下载完成后点击不会进来。     */    public class NotificationClickReceiver extends BroadcastReceiver {        @Override        public void onReceive(Context context, Intent intent) {            long[] completeIds = intent.getLongArrayExtra(                    DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS);            //正在下载的任务ID            long downloadTaskId = TDevice.getDownloadTaskId(context);            if (completeIds == null || completeIds.length <= 0) {                openDownloadsPage(appContext);                return;            }            for (long completeId : completeIds) {                if (completeId == downloadTaskId) {                    openDownloadsPage(appContext);                    break;                }            }        }        /**         * Open the Activity which shows a list of all downloads.         *         * @param context 上下文         */        private void openDownloadsPage(Context context) {            Intent pageView = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);            pageView.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);            context.startActivity(pageView);        }    }}

Android7.0适配

1.在manifest文件application标签中中加入

<provider            android:name="android.support.v4.content.FileProvider"            android:authorities="net.xxx.app.provider"             /**注意参数统一性 FileProvider.getUriForFile(appContext, "net.xxx.app.provider", apkFile);*/                        android:exported="false"            android:grantUriPermissions="true">            <meta-data                android:name="android.support.FILE_PROVIDER_PATHS"                android:resource="@xml/provider_paths" />        </provider>

2.res下的xml文件夹中的provider_paths源码

<?xml version="1.0" encoding="utf-8"?><paths>    <!--path:需要临时授权访问的路径(.代表所有路径) name:就是你给这个访问路径起个名字-->    <external-path        name="external_files"        path="." /></paths>

参考:
1.https://github.com/oschina/android-app
2.http://www.jianshu.com/p/98ea7e866ffd

原创粉丝点击