webview下载操作的踩坑记录
背景记录
由于公司需要, 需要在在webview中执行下载操作, 而且下载完成之后还需要跳转到自动安装页面~~~~
接下来就是踩坑报告
1.webview执行下载操作
思路
经过查找资料发现webview有三种下载方式
- 1,跳转到浏览器进行下载
- 2,使用系统服务进行下载
- 3,自定义下载任务进行下载
发现跳转到浏览器进行下载最简单,但是做完之后领导说这样不行,要在咱们app内部进行下载.于是就开始进行修改~~~~
在余下的两种方法中进行选择,发现还是使用系统服务进行下载比较简单
于是就开始调试
实现
根据看api和在网上查找资料之后发现webview有一个下载的监听
webView.setDownloadListener(new DownloadListener() {
@Override
public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
});
- onDownloadStart参数
- url 访问的下载链接
- userAgent HTTP请求头部用来标识客户端信息的字符串
- contentDisposition 保存文件提供一个默认的文件名
- mimetype 资源的媒体类型
- contentLength 资源的大小
不在多说,直接贴下载代码
webView.setDownloadListener(new DownloadListener() {
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onDownloadStart(final String url, String userAgent, final String contentDisposition, final String mimetype, long contentLength) {
/**
android6.0之上需要适配动态权限获取
6.0之下则不需要进行适配
别忘了在AndroidManifest.xml中配置网络权限和外置存储读写权限
这个地方我没有进行适配,如果直接复制的话需要自己手动添加权限获取
*/
// 指定下载地址
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
// 允许媒体扫描,根据下载的文件类型被加入相册、音乐等媒体库
request.allowScanningByMediaScanner();
// 设置通知的显示类型,下载进行时和完成后显示通知
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
// 允许在计费流量下下载
request.setAllowedOverMetered(false);
// 允许该记录在下载管理界面可见
request.setVisibleInDownloadsUi(true);
// 允许漫游时下载
request.setAllowedOverRoaming(true);
// 允许下载的网路类型
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
// 设置下载文件保存的路径和文件名
String fileName = URLUtil.guessFileName(url, contentDisposition, mimetype);
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);
// 另外可选一下方法,自定义下载路径
// request.setDestinationUri()
// request.setDestinationInExternalFilesDir()
final DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
// 添加一个下载任务
long downloadId = downloadManager.enqueue(request);
}
});
就这样就完成了在webview中实现下载
在这算是下载实现完成
下载完成之后自动安装
系统下载服务,在下载完成之后会发送一条广播,在广播中会有任务ID
我们就可以通过DownloadManager获取到具体的文件信息,进行apk的安装处理.
废话不多说直接上代码
我这里是新建Receiver进行监听,具体实现安装任务
也可以使用内部类的方法进行实现
public class DownloadReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent != null) {
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(intent.getAction())) {
//获取downloadId
long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
// Log.e("downloadId:{}", downloadId+"<><>");
// 获取下载管理器,文件的具体信息都在这个里面
DownloadManager downloadManager = (DownloadManager) context.getSystemService(DOWNLOAD_SERVICE);
//获取type
String type = downloadManager.getMimeTypeForDownloadedFile(downloadId);
// Log.e("eForDownloadedFile:{}", type);
if (TextUtils.isEmpty(type)) {
type = "*/*";
}
//获取文件uri
//android7获取的是content格式
//android7之下获取的file:///格式
Uri uri = downloadManager.getUriForDownloadedFile(downloadId);
Log.e("UriForDownloadedFile:{}", uri.toString());
if (uri != null) {
//8.0之前适用
//Intent handlerIntent = new Intent(Intent.ACTION_VIEW);
//8.0之后适用,向下兼容
Intent handlerIntent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
//适配android7之上的版本
//如果不做适配则不会进行自动安装
//需要对文件所对应的uri进行临时授权
//如果低于android7的话则不用进行
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // 适配Android 7系统版本
handlerIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加这一句表示对目标应用临时授权该Uri所代表的文件
}
handlerIntent.setDataAndType(uri, type);
handlerIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(handlerIntent);
}
}
}
}
}
代码片段中注释很详细这就不进行详细介绍
需要的权限
android6之后需要动态获取权限,否则活报错
<!--读取写入权限-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--android7之后安装文件权限-->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
provider处理
需要在res文件下新建xml文件夹,在xml文件夹下新建file_paths.xml
有其他的需要可以在进行添加
<external-path
name="files_root"
path="Android/data/" />
<external-files-path name="external_files_path" path="Download" />
在AndroidManifest.xml中添加代码
<application
...
...>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
到此坑踩了不少,中间也填了一些,如果还有什么bug发现的朋友们可以提出来看,一块进行修改