DownloadManager和FileProvider在8.0中的坑

姚高爽
2023-12-01

近期项目做适配8.0,坑不断呀。首先 介绍下7.0和8.0中的一些修改,在7.0的中有共享文件的限制,对外提供的文件,不能显示文件路径;在8.0中限制了广播的注册方式,取消大部分静态注册广播。这些都是基本操作了,同时还有一些厂商自己的修改,以下只介绍项目中遇到的坑,如部分华为系统对DownloadManager中的网络有限制要求,在下载的是时候要设置好是wifi还是数据网络,不然免谈,最后说下一个卡了好久的大坑Android 8.0 Oreo 中,Google 移除掉了容易被滥用的“允许位置来源”应用的开关,在安装 Play Store 之外的第三方来源的 Android 应用的时候,竟然没有了“允许未知来源”的检查框,如果你还是想要安装某个被自己所信任的开发者的 app,则需要在每一次都手动授予“安装未知应用”的许可,这个不是重点。重点是到了安装的时候界面的只是一闪而过,没有任何提示,任何报错,完全是轻飘飘的来,轻飘飘的走,啥也不留下,问题都不知道怎么查。

坑已经介绍完,开始填坑,第一个坑广播坑监听安装完成广播,需要动态注册,单例加判空处理只注册一次

//初始化的时候判断是否为空,为空才将它初始化,这样就能保证始终存在一个。
if (snDownloadReceiver == null) {
    intentFilter = new IntentFilter();
    intentFilter.addAction("android.intent.action.DOWNLOAD_COMPLETE");
    intentFilter.addAction("android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED");
    snDownloadReceiver = new SnDownloadReceiver();

    GlobalContext.getInstance().context.registerReceiver(snDownloadReceiver, intentFilter);
}

第二个坑文件共享的坑首先在mainfest中配置

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="${applicationId}.android7.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
       android:name="android.support.FILE_PROVIDER_PATHS"
       android:resource="@xml/file_paths" />
</provider>

之后在res目录下创建一个xml文件夹同时创建一个xml文件命名file_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <!--
        该方式提供在应用的外部存储区根目录的下的文件。
                             它对应Context#getExternalFilesDir(String) Context.getExternalFilesDir(null)
                             返回的路径。eg:”/storage/emulated/0/Android/data/com.jph.simple/files”
    -->
    <external-files-path
        name="external_file_path"
        path="Download/" />
</paths>

接着就看文件intent启动文件的地方

Intent intent = new Intent(Intent.ACTION_VIEW);
File apkFile = new File(GlobalContext.getInstance().getDownloadPath());
if (!apkFile.exists()) {
	return;
}
//判断是否是AndroidN以及更高的版本
if (GlobalContext.getInstance().context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.N) {
	// 由于没有在Activity环境下启动Activity,设置下面的标签
	intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
	//添加这一句表示对目标应用临时授权该Uri所代表的文件
	intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
	Uri contentUri = android.support.v4.content.FileProvider.getUriForFile(GlobalContext.getInstance().context, GlobalContext.getInstance().context.getPackageName() + ".android7.fileprovider", apkFile);
	intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
} else {
	intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
	intent.setDataAndType(Uri.parse("file://" + apkFile.getAbsolutePath()), "application/vnd.android.package-archive");
}
GlobalContext.getInstance().context.startActivity(intent);

第二个坑已经完成,之后就是华为限制了downloadmanager下载的坑,在下载之前对网络进行检测,记载网络类型,网络是否可用

private static boolean isNetworkOnline() {
	Runtime runtime = Runtime.getRuntime();
	try {
		Process ipProcess = runtime.exec("ping -c 1 fiapp.suning.com");
		if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
			boolean exitValue = ipProcess.waitFor(800, TimeUnit.MILLISECONDS);
			return exitValue;
		} else {
			int exitValue = ipProcess.waitFor();
			return (exitValue == 0);
		}
	} catch (IOException | InterruptedException e) {
		e.printStackTrace();
	}
	return false;
}   
	   
public static boolean isNetConnect() {
	try {
		ConnectivityManager connectivityManager = (ConnectivityManager) GlobalContext.getInstance().context.getSystemService(Context.CONNECTIVITY_SERVICE);
		NetworkInfo info = connectivityManager.getActiveNetworkInfo();

		if (info != null && info.isConnected()) {
            //根据目前连接的网络设置网络类型
			if (info.getType() == ConnectivityManager.TYPE_WIFI) {
				PayHelper.getInstance().setNetType(DownloadManager.Request.NETWORK_WIFI);
			} else {
				PayHelper.getInstance().setNetType(DownloadManager.Request.NETWORK_MOBILE);
			} 
			return true;
		}
	} catch (Exception e) {
		return false;
	}
	return false;
}

public static void downloadApk(Context context, String url) {
	if (!isNetConnect() || !isNetworkOnline()) {
		ToastUtil.showMessage(context.getResources().getString(R.string.snpay_no_internet));
		return;
	}

	String serviceNameInString = Context.DOWNLOAD_SERVICE;
	DownloadManager downloadManager = (DownloadManager) context.getSystemService(serviceNameInString);
	Uri uri = Uri.parse(url);
	DownloadManager.Request request = new DownloadManager.Request(uri);
	/设置网络
	request.setAllowedNetworkTypes(PayHelper.getInstance().getNetType());

	//在通知栏中显示
	request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
	request.setTitle("下载中...");
	request.setVisibleInDownloadsUi(true);
	//此处要和增加的xml文件中对应使用
	File destFile = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "epa.apk");
	if (destFile.exists()) {
		destFile.delete();
	}
	request.setDestinationUri(Uri.parse("file://" + destFile.getAbsolutePath()));
	//获得唯一下载id
	long reqId = downloadManager.enqueue(request);
	GlobalContext.getInstance().setDownloadId(reqId);
	GlobalContext.getInstance().setDownloadPath(destFile.getPath());
}

好了还有最后一个坑就是8.0限制外部应用安装的问题,解决很简单

<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

 

 类似资料: