前言

  • 在android应用开发中经常会遇到应用升级和下载第三方应用的需求。
  • 这篇博客介绍了关于下apk获取写入权限问题。和7.0以及7.0以上版本的手机读取不到apk而无法安装的问题。
  • 该下载方式适应各种版本,处理了一系列遇到的问题。

download components android 下载很慢 安卓downloadmanager_DownloadManager


正文

Activity类

/**
 *
 * 这demo有两个地方比较重要
 * 1,下载apk的地址,这里决定了6.0和以上的额版本是否需要使用动态写入权限。
 * 2,在DownloadManagerUtil类里面的StrictMode的使用。这将决定7.0以及7.0以上的系统是否能读取到apk文件并启动安装。
 */
public class MainActivity extends Activity {
    private String url = "http://p.gdown.baidu.com/2c94946f0e26ae462034226fde89692a269f6bdf2aa6e9c8767d772124c9f7c7d260e6931fef78f570c881e16b38ef5c2078652c803b022fe844fb87d68c894ddbef8a9694a05f1e0ff373231ca712808c4440578d04145cdba6bc15f63a58840b47586cd429087098129921afed1197f1295b0f2cf49ff9250a04c0d4ef1ae92fdb5712c98e32f6be819bd5d37ee48e968923ef76a8cc7fb9742033e72b07c84dd4e14dc8d7931011e1242b1a867296948cf07eaea2a39a3dfd57541fe83eade2e5b448b9ba397e0a84fc90bc2405b969c9634da0803afc6b0464e4a7e333bb0c7072bd418e99312b5457043c33f156a13660aba0be6f15";//较小的apk文件
    private String url2 = "http://mhhy.dl.gxpan.cn/apk/ml/MBGYD092101/Gardenscapes-ledou-MBGYD092101.apk";//梦幻花园游戏包体较大,可以很好的查看下载效果

    private String title = "应用宝";//这里可以写应用名
    private String desc = "大量优质应用,尽在应用宝。";//这里填写一些对应用的介绍
    long downloadId = 0;
    DownloadManagerUtil downloadManagerUtil;
    private boolean isRegisterReceiver;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        PublicUtile.getInstance().setmActivity(this);
        setReceiver();

        RelativeLayout rlParentContainer = new RelativeLayout(this.getApplicationContext());
        setContentView(rlParentContainer);

        RelativeLayout.LayoutParams rlp_tv = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        rlp_tv.addRule(RelativeLayout.CENTER_HORIZONTAL);
        TextView tv = new TextView(this.getApplicationContext());
        tv.setText("DownLoadManager Test");
        rlParentContainer.addView(tv, rlp_tv);


        RelativeLayout.LayoutParams rlp_button = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        rlp_button.addRule(RelativeLayout.CENTER_IN_PARENT);
        Button download = new Button(this.getApplicationContext());
        download.setText("开始下载...");
        rlParentContainer.addView(download, rlp_button);


        downloadManagerUtil = new DownloadManagerUtil(this);

        download.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //调起系统下载功能
                if (downloadId != 0) {
                    downloadManagerUtil.clearCurrentTask(downloadId);
                }
                downloadId = downloadManagerUtil.download(url, title, desc);
            }
        });
    }


    /**
     * 注册下载成功的广播监听
     */
    private void setReceiver() {
        if (!isRegisterReceiver) {
            DownloadReceiver receiver = new DownloadReceiver();
            IntentFilter intentFilter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
            this.registerReceiver(receiver, intentFilter);
            isRegisterReceiver = true;
        }
    }}
/**
 * Created by lenovo on 2018/6/17.
 * 下载成功广播类
 */
public class DownloadReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
            long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
            installApk(context, id, PublicUtile.getApkDownPath(context) + PublicUtile.TestApkName);
        } 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);
        }
    }

    /**
     * 启动安装
     *
     * @param context
     * @param downloadApkId
     * @param apkPath
     */
    private static void installApk(Context context, long downloadApkId, String apkPath) {
        DownloadManager dManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
        Intent install = new Intent(Intent.ACTION_VIEW);
        Uri downloadFileUri = dManager.getUriForDownloadedFile(downloadApkId);
        if (downloadFileUri != null) {
            Log.e("DownloadManager", downloadFileUri.toString());
            install.setDataAndType(Uri.parse("file://" + apkPath), "application/vnd.android.package-archive");
            install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(install);
        } else {
            Log.e("DownloadManager", "download error");
        }
    }
}
/**
 * Created by lenovo on 2018/6/17.
 * 下载类
 */
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
//        req.setDestinationInExternalFilesDir(mContext, Environment.DIRECTORY_DOWNLOADS, title);
//        //通知栏标题
//        req.setTitle(title);
//        //通知栏描述信息
//        req.setDescription(desc);
//        //设置类型为.apk
//        req.setMimeType("application/vnd.android.package-archive");
//        //获取下载任务ID
//        DownloadManager dm = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
//        return dm.enqueue(req);
//    }


    /**
     * 比较实用的升级版下载功能
     *
     * @param url   下载地址
     * @param title 文件名字
     * @param desc  文件路径
     */
    public long download(String url, String title, String desc) {
        DownloadManager downloadManager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
        long ID;

        //以下两行代码可以让下载的apk文件被直接安装而不用使用Fileprovider,系统7.0或者以上才启动。
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            StrictMode.VmPolicy.Builder localBuilder = new StrictMode.VmPolicy.Builder();
            StrictMode.setVmPolicy(localBuilder.build());
        }

        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
        // 仅允许在WIFI连接情况下下载
//        request.setAllowedNetworkTypes(Request.NETWORK_WIFI);
        // 通知栏中将出现的内容
        request.setTitle(title);
        request.setDescription(desc);

        //7.0以上的系统适配
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            request.setRequiresDeviceIdle(false);
            request.setRequiresCharging(false);
        }

        //制定下载的文件类型为APK
        request.setMimeType("application/vnd.android.package-archive");

        // 下载过程和下载完成后通知栏有通知消息。
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE | DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);

        // 指定下载文件地址,使用这个指定地址可不需要WRITE_EXTERNAL_STORAGE权限。
        request.setDestinationUri(Uri.fromFile(new File(PublicUtile.getApkDownPath(mContext) + PublicUtile.TestApkName)));

        //大于11版本手机允许扫描
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            //表示允许MediaScanner扫描到这个文件,默认不允许。
            request.allowScanningByMediaScanner();
        }

        Activity activity = PublicUtile.getInstance().getmActivity();
        if (activity != null) {
            activity.startActivity(new android.content.Intent(DownloadManager.ACTION_VIEW_DOWNLOADS));//启动系统下载界面
        }
        ID = downloadManager.enqueue(request);
        return ID;
    }

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

以上为重要代码。

最后如果有更好的实现方式或者有其他问题,欢迎在评论区留言交流。