Android 利用系统下载管理器下载apk

1、定义一个下载工具类

public class DownloadManagerUtil {
    private Context mContext;

    public DownloadManagerUtil(Context context) {
        mContext = context;
    }

    public long download(String url, String title, String desc) {
        Uri uri = Uri.parse(url);
        DownloadManager.Request req = new DownloadManager.Request(uri);
        //设置WIFI下进行更新
        //req.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
        //下载中和下载完后都显示通知栏
        req.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        //使用系统默认的下载路径 此处为应用内 /android/data/packages ,所以兼容7.0
        String apkName;
        if(url.endsWith(".apk")){
            apkName = url.substring(url.lastIndexOf("/"));
        }else {
            apkName = "sswl_game_"+System.currentTimeMillis()+".apk";
        }
        req.setDestinationInExternalFilesDir(mContext, Environment.DIRECTORY_DOWNLOADS, apkName);
        req.setVisibleInDownloadsUi(true);
        //通知栏标题
        req.setTitle(title);
        //通知栏描述信息
        req.setDescription(desc);
        //设置类型为.apk
        req.setMimeType("application/vnd.android.package-archive");

        //获取下载任务ID
        DownloadManager dm = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
        long loadId = dm.enqueue(req);
        Log.i("min77","loadId = "+loadId);
        return loadId;
    }

    /**
     * 下载前先移除前一个任务,防止重复下载
     *
     * @param downloadId
     */
    public void clearCurrentTask(long downloadId) {
        DownloadManager dm = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
        try {
            dm.remove(downloadId);
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace();
        }
    }
}

2、定义一个receiver接收下载进度的广播

public class DownloadReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
            //下载完成跳转去安装apk
            long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
            installApk(context, id);
        } else if (intent.getAction().equals(DownloadManager.ACTION_NOTIFICATION_CLICKED)) {
            //处理 如果还未完成下载,用户点击Notification ,跳转到下载中心
            Intent viewDownloadIntent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);
            viewDownloadIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(viewDownloadIntent);
        }
    }

    private static void installApk(Context context, long downloadApkId) {
        try {
            DownloadManager dm = (DownloadManager)context.getSystemService(Context.DOWNLOAD_SERVICE);
            Intent paramIntent = new Intent("android.intent.action.VIEW");
            //获取当前下载id数据库游标
            Cursor cursor = dm.query(new DownloadManager.Query().setFilterById(new long[] { downloadApkId }));
            cursor.moveToFirst();
            //获取下载apk文件uri的列数
            int fileUriIdx = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI);
            //获取下载apk文件uri
            String fileUri = cursor.getString(fileUriIdx);
            paramIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            Uri uri;
            // 7.0+ 需要将file://的uri转换为更安全的content://,并且增加读取uri权限
            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
                String path="";
                if (fileUri != null) {
                    path = Uri.parse(fileUri).getPath();
                }
                uri = FileProvider.getUriForFile(context, context.getPackageName() + ".sswl.provider", new File(path));
                paramIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    //            //兼容8.0
    //            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    //                boolean hasInstallPermission = context.getPackageManager().canRequestPackageInstalls();
    //                if (!hasInstallPermission) {
    //                    startInstallPermissionSettingActivity(context);
    //                    return;
    //                }
    //            }
            }else {
                uri = Uri.parse(fileUri);
            }
            //设置打开apk格式文件
            paramIntent.setDataAndType(uri, "application/vnd.android.package-archive");

            if(!TextUtils.isEmpty(DownloadManagerUtil.apkMd5)){
                //服务端有下发MD5
                ParcelFileDescriptor parcelFileDescriptor = context.getContentResolver().openFileDescriptor(uri, "rw");
                FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
                fileDescriptor.sync();
                if(fileDescriptor.valid()){
                    //正常获取到fileDescriptor对象
                    FileInputStream fis = new FileInputStream(fileDescriptor);
                    String md5 = Md5Utils.getFileMD5(fis);
                    Log.i("min77","md5 = "+md5);
                    if (DownloadManagerUtil.apkMd5.equalsIgnoreCase(md5)) {
                        //计算出的MD5一致
                        handleDownloadedApk(context, paramIntent);
                    }else {
                        ToastUtils.show(context, ResourceUtil.getString(context,"com_sswl_apk_md5_error"));
                        // 要是系统下载器下载的apk MD5不对,则跳转到外部浏览器下载
                        Uri uri1 = Uri.parse(DownloadManagerUtil.downloadUrl);
                        Intent intent = new Intent(Intent.ACTION_VIEW, uri1);
                        context.startActivity(intent);
                    }

                }else {
                    handleDownloadedApk(context, paramIntent);
                    Log.e("min77"," fileDescriptor1.valid() = "+fileDescriptor.valid());
                }
            }else {
                handleDownloadedApk(context, paramIntent);
            }



        } catch (Exception e) {
            e.printStackTrace();
            openLocalDir(context);
        }
    }

    /**
     * 处理下载好的apk
     * @param context
     * @param paramIntent
     */
    private static void handleDownloadedApk(Context context, Intent paramIntent) {
        if (paramIntent.resolveActivity(context.getPackageManager()) != null) {  
            //存在安装apk的activity,则打开安装界面
            context.startActivity(paramIntent);
        } else {
            //不存在安装apk的activity,则打开apk所在目录
            openLocalDir(context);
        }
        DownloadManagerUtil.apkMd5 = "";
    }

    /**
     * 跳转到设置-允许安装未知来源-页面
     */
    @TargetApi(Build.VERSION_CODES.O)
    private static void startInstallPermissionSettingActivity(Context context) {
        //后面跟上包名,可以直接跳转到对应APP的未知来源权限设置界面。使用startActivityForResult 是为了在关闭设置界面之后,获取用户的操作结果,然后根据结果做其他处理
        Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, Uri.parse("package:" + context.getPackageName()));
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }

    private static void openLocalDir(Context context){
        //调用系统文件管理器打开指定路径目录
        //获取到指定文件夹,这里为:/storage/emulated/0/Android/data/你的包	名/files/Download
        File file = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        //7.0以上跳转系统文件需用FileProvider,参考链接:https://blog.csdn.net/growing_tree/article/details/71190741
        Uri uri = FileProvider.getUriForFile(context,context.getPackageName() + ".sswl.provider",file);
        intent.setData(uri);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }

2、记得在AndroidManifest.xml中声明
1)声明访问网络权限、读写外部存储权限、安装apk权限

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <!-- android 8.0+ 需要这个权限才能安装apk -->
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

2)声明receiver下载广播接收器

 <receiver android:name=".receiver.DownloadReceiver">
      <intent-filter>
             <action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
             <action android:name="android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED" />
       </intent-filter>
 </receiver>
发布了36 篇原创文章 · 获赞 9 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_43278826/article/details/88707587