Unknown URL content://downloads/my_downloads 三星引发的血案

这是一个使用DownloadManager在三星手机引发的血案。

定义:
DownloadManager是从API 9开始加入的,用来处理http长连接的一个系统服务,我们可以使用它请求一个URI来下载到一个目标文件。DownloadManager会把下载放在后台执行,并且会在http连接失败后一旦网络恢复或者系统重启时自动尝试重新下载。我们可以通过contex.getSystemService(DOWNLOAD_SERVICE)获得一个DownloadManager实例。

场景:
每个app里面都会用到下载功能,谷歌也考虑到了这个问题,所以给我们提供了DownloadManager这个下载器来进行下载管理。下面是我用到的主要跟下载有关的代码(完整代码网上很多这里不提供了,主要说说遇到的问题):

public static void installUpdateApk(final String url,
            final String fileName, final String description) {
        new Thread() {

            public void run() {
                Looper.prepare();
                try {
                    download(url, fileName, description);
                } catch (Exception e) {
                    APK_DOWNLOADING = false;
                    e.printStackTrace();
                }
            }

            @SuppressWarnings("deprecation")
            @SuppressLint({ "InlinedApi", "NewApi" })
            private void download(final String url, String fileName,
                    String description) {
                File d = new File(AppConfig.DOWNLOAD_DIR);
                if (!d.exists()) {
                    d.mkdirs();
                }
                File f = new File(AppConfig.DOWNLOAD_DIR + fileName);
                if (f.exists()) {
                    f.delete();
                }
                APK_DOWNLOADING = true;
                if (mContext == null) {
                    APK_DOWNLOADING = false;
                    return;
                }
                String downloadUrl = url;
                if (downloadUrl == null) {
                    APK_DOWNLOADING = false;
                    Toast.makeText(mContext, "下载失败!", Toast.LENGTH_LONG).show();
                    return;
                }
                // check if support download manager
                if (!isDownloadManagerAvailable(mContext)) {

                    Intent intent = new Intent();
                    intent.setAction("android.intent.action.VIEW");
                    Uri content_url = Uri.parse(downloadUrl);
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    intent.setData(content_url);
                    mContext.startActivity(intent);
                    APK_DOWNLOADING = false;
                    return;
                }
                manager = (DownloadManager) mContext
                        .getSystemService(Context.DOWNLOAD_SERVICE);
                // 创建下载请求
                DownloadManager.Request down = new DownloadManager.Request(
                        Uri.parse(downloadUrl));
                // 设置允许使用的网络类型,这里是移动网络和wifi都可以
                // down.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
                down.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE
                        | DownloadManager.Request.NETWORK_WIFI);

                down.setMimeType("application/vnd.android.package-archive");
                down.setDescription(description);
                // 禁止发出通知,既后台下载
                down.setShowRunningNotification(true);
                // 不显示下载界面
                down.setVisibleInDownloadsUi(true);
                down.setDestinationInExternalPublicDir(
                        AppConfig.PROJECT_FOLDER_NAME + "/download",
                        fileName);

                // 将下载请求放入队列
                manager.enqueue(down);
            }
        }.start();
    }
public static boolean isDownloadManagerAvailable(Context context) {
        try {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
                return false;
            }
            return true;
        } catch (Exception e) {
            return false;
        }
    }

遇到的问题:
既然知道是从api 9 后才加入的所以用isDownloadManagerAvailable() 方法做下判断如果是低版本则采用浏览器的方式下载。一般这么做判断后大部分手机是没有问题的。可是实际使用总会带给我们惊喜,某一天一个同事拿着一个三星手机来告诉我下载不好用了,无奈经过调试后发现报如标题所示的错误了,最后经过查找才发现原来它手机里面装了手机卫士,系统自带的下载管理器被禁用了(这里我就**了)!

解决方案:
还好办法总会多过问题,为了防止其他手机会出现类似的问题,这里采用的是判断系统的下载器是否可用进而选择下载方式。通过context.getPackageManager().getApplicationEnabledSetting("com.android.providers.downloads") 这个方法我们能得到系统反馈的信息有:0、1、2、3、4。 通过查找源码具体如下:

在PackageManager类里:

/**
     * Flag for {@link #setApplicationEnabledSetting(String, int, int)}
     * and {@link #setComponentEnabledSetting(ComponentName, int, int)}: This
     * component or application is in its default enabled state (as specified
     * in its manifest).
     */
    public static final int COMPONENT_ENABLED_STATE_DEFAULT = 0;

    /**
     * Flag for {@link #setApplicationEnabledSetting(String, int, int)}
     * and {@link #setComponentEnabledSetting(ComponentName, int, int)}: This
     * component or application has been explictily enabled, regardless of
     * what it has specified in its manifest.
     */
    public static final int COMPONENT_ENABLED_STATE_ENABLED = 1;

    /**
     * Flag for {@link #setApplicationEnabledSetting(String, int, int)}
     * and {@link #setComponentEnabledSetting(ComponentName, int, int)}: This
     * component or application has been explicitly disabled, regardless of
     * what it has specified in its manifest.
     */
    public static final int COMPONENT_ENABLED_STATE_DISABLED = 2;

    /**
     * Flag for {@link #setApplicationEnabledSetting(String, int, int)} only: The
     * user has explicitly disabled the application, regardless of what it has
     * specified in its manifest.  Because this is due to the user's request,
     * they may re-enable it if desired through the appropriate system UI.  This
     * option currently <strong>cannot</strong> be used with
     * {@link #setComponentEnabledSetting(ComponentName, int, int)}.
     */
    public static final int COMPONENT_ENABLED_STATE_DISABLED_USER = 3;

    /**
     * Flag for {@link #setApplicationEnabledSetting(String, int, int)} only: This
     * application should be considered, until the point where the user actually
     * wants to use it.  This means that it will not normally show up to the user
     * (such as in the launcher), but various parts of the user interface can
     * use {@link #GET_DISABLED_UNTIL_USED_COMPONENTS} to still see it and allow
     * the user to select it (as for example an IME, device admin, etc).  Such code,
     * once the user has selected the app, should at that point also make it enabled.
     * This option currently <strong>can not</strong> be used with
     * {@link #setComponentEnabledSetting(ComponentName, int, int)}.
     */
    public static final int COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED = 4;

这里简单说下 0:只要在AndroidManifest里面开启了网络访问权限则为可用状态。
1:不管是否在AndroidManifest开启了权限都为可用状态。
2:不管是否在AndroidManifest开启了权限都为不可用状态。
3:用户禁止使用状态。
4:用户不选择允许使用之前都不可用状态。

由此可以看出只有状态为0 或者1 的时候我们的app才能正常使用DownloadManager,这样我们就可以做判断了,只需要改下isDownloadManagerAvailable 方法 如下:

public static boolean isDownloadManagerAvailable(Context context) {
        try {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD
                    || context.getPackageManager()
                            .getApplicationEnabledSetting(
                                    "com.android.providers.downloads") == context
                            .getPackageManager().COMPONENT_ENABLED_STATE_DISABLED_USER
                    || context.getPackageManager()
                            .getApplicationEnabledSetting(
                                    "com.android.providers.downloads") == context
                            .getPackageManager().COMPONENT_ENABLED_STATE_DISABLED
                    || context.getPackageManager()
                            .getApplicationEnabledSetting(
                                    "com.android.providers.downloads") == context
                        .getPackageManager().COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED ) {

                return false;
            }
            return true;
        } catch (Exception e) {
            return false;
        }
    }

好了以上就是本人在使用DownloadManager的时候遇到的问题,特此在这里做下记录。 (-_-) !

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值