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

说明:

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

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值