<上一篇 Android 开发-使用腾讯TBS浏览服务 X5webview控件
该篇我们需要实现的是下载网络文件到本地,这里暂时不提供解压。后续还会将这些下载记录用sqlite保存本地。
1、首先我们需要定义保存目录位置,建议使用app私有目录,不要放在公有目录,因为现在Android对公有目录逐渐开始控制,也避免给用户造成不必要的存储垃圾。
private WebView mWebView;
private final int hand_js_doJsFunction = 1;
private Context mContext;
//private DbFileInfoService dbFileServer;数据库存储服务
//private final int dbversion = 1;
private String app_downLoadPath = "";
public static List<String> downFileList = new ArrayList<String>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view);
IniteWebView();
mContext = getApplicationContext();
app_downLoadPath = getBaseDir(mContext) + "/download/";//下载到app私有目录
//dbFileServer = new DbFileInfoService(mContext,dbversion);
}
private static String getBaseDir(Context context) {
String externalStoragePublicDirectory = context.getExternalFilesDir("").getAbsolutePath();// Environment.MEDIA_MOUNTEDEnvironment.getExternalFilesDir(Environment.DIRECTORY_PICTURES).getAbsolutePath();
File dir = new File(externalStoragePublicDirectory);
if (!dir.exists()) {
dir.mkdirs();
}
return externalStoragePublicDirectory;
}
2、与js交互方法添加一个下载接口
@JavascriptInterface
public void downloadFile(String path,String appId,String productId,String cfgName,String productName,String imgUrl) { //文件下载
try {
String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE};
if( OpenPermissions(permissions,true)){
return;
}
FileDownLoadInfo _model = new FileDownLoadInfo(appId,cfgName,Integer.parseInt(productId),productName,imgUrl,"");
DownloadFile(_model,path);
}catch (Exception e)
{
}
}
3、这里我们由于下载文件需要对文件进行读写。需要添加权限申请
public void showToastTips(String msg){
//Toast.makeText(getApplicationContext(),msg,Toast.LENGTH_LONG).show();
Toast toast = Toast.makeText(getApplicationContext(),null,Toast.LENGTH_LONG);
toast.setText(msg);
toast.show();
}
protected boolean OpenPermissions(String[] permissions ,boolean isShowTips ){
if (Build.VERSION.SDK_INT >= 23) {
int REQUEST_CODE_CONTACT = 103;
List<String> mPermissionList = new ArrayList<>();
//验证是否许可权限
for (String str : permissions) {
if (this.checkSelfPermission(str) != PackageManager.PERMISSION_GRANTED) {
//申请权限
mPermissionList.add(str);
}
}
if(mPermissionList.size() > 0){
if(isShowTips){
showToastTips("权限不足!");
}
// String[] permissions = mPermissionList.toArray(new String[mPermissionList.size()]);//将List转为数组
this.requestPermissions( mPermissionList.toArray(new String[mPermissionList.size()]), REQUEST_CODE_CONTACT);
return true;
}
}
return false;
}
//区别于 OpenPermissions 方法的是,本方法不进行权限请求;首页会进行一次权限的请求
protected boolean permissionNoGranted(String[] permissions ,boolean isShowTips ){
if (Build.VERSION.SDK_INT >= 23) {
int REQUEST_CODE_CONTACT = 103;
List<String> mPermissionList = new ArrayList<>();
//验证是否许可权限
for (String str : permissions) {
if (this.checkSelfPermission(str) != PackageManager.PERMISSION_GRANTED) {
//申请权限
mPermissionList.add(str);
}
}
if(mPermissionList.size() > 0){
if(isShowTips){
showToastTips("权限不足!");
}
return true;
}
}
return false;
}
4、下载由于会消耗比较多的资源,建议使用线程下载处理
//region description== download ==function==============================================================
public void DownloadFile(FileDownLoadInfo _model,String path){
if(!downFileList.contains(path)){
new DownloadAsyncTas(_model).execute(path);
downFileList.add(path);
}
}
private boolean isLoad = false;
private final int FILE_SIZE = 0;
private final int DOWNLOAD_PROGRESS = 1;
private final int DOWNLOAD_START = 4;
private final int DOWNLOAD_SUCCESS = 2;
private final int DOWNLOAD_FAIL = 3;
class DownloadAsyncTas extends AsyncTask<String, Integer, Integer> {
String fileID = "";
String name = "";
String downloadPath = "";
FileDownLoadInfo fileInfo = null ;
long completeLen = -1;
String saveFilePath = "";
DownloadAsyncTas(FileDownLoadInfo _fileInfo){
fileInfo = _fileInfo;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
isLoad = true;
// setHand(hand_js_downLoadBegin);
}
@Override
protected Integer doInBackground(String... params) {
//完成下载任务
downloadPath = params[0];//这是从execute方法中传过来的参数, 即下载的地址
try {
// s = "http://115.238.91.202:3181/images/2.jpg";
URL url = new URL(downloadPath);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5*1000);
conn.setReadTimeout(5000);
conn.setRequestMethod("GET");
if (conn.getResponseCode() == 200) {
String file = conn.getURL().getFile();
String _express = FileUtility.getExtensionFromFilename(downloadPath);
fileInfo.productName = fileInfo.productName+ "_" + fileInfo.cfgName + "_" + fileInfo.appId + _express;;//+ "_" + fileInfo.productId
String fileName = fileInfo.productName;//file.substring(file.lastIndexOf('/')+1);
// if(!fileName.toLowerCase().endsWith(_express)){
// fileName = fileName + _express;
// }
if(fileInfo != null){//断点续传
String dir = app_downLoadPath;// + fileInfo.productId + "_" + fileInfo.cfgName + "/";
saveFilePath = dir + fileName;
FileUtility.checkPath(saveFilePath);
File info = new File(saveFilePath);
if(info.exists()){
info.delete();
}
int size = conn.getContentLength();//获取到最大值之后设置到进度条的MAX
publishProgress(FILE_SIZE, size);
//开始下载
byte[] bytes = new byte[1024];//可以设置大点提高下载速度
int len = -1;
InputStream in = conn.getInputStream();
boolean append = false;
if(completeLen > 0){
in.skip(completeLen);
append = true;
}
FileOutputStream out = new FileOutputStream(saveFilePath,append);
while( (len = in.read(bytes)) != -1 ){
out.write(bytes, 0, len);
completeLen += len;
publishProgress(DOWNLOAD_PROGRESS, len);
out.flush();
}
out.close();
in.close();
}else{
return DOWNLOAD_FAIL;
}
}else{
return DOWNLOAD_FAIL;
}
} catch (Exception e) {
return DOWNLOAD_FAIL;
}
return DOWNLOAD_SUCCESS;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
switch (values[0]){
case FILE_SIZE:
// _progress.setMax(values[1]);
break;
case DOWNLOAD_PROGRESS:
// _progress.incrementProgressBy(values[1]);
break;
case DOWNLOAD_START:
//_progress.setInfo(values[1], true);
break;
}
}
@Override
protected void onPostExecute(Integer integer) {
super.onPostExecute(integer);
isLoad = false;
downFileList.remove(downloadPath);
try {
if(integer == DOWNLOAD_SUCCESS){
downLoadComplete(true,fileInfo);
}else if(integer == DOWNLOAD_FAIL){
downLoadComplete(false,fileInfo);
}
}catch (Exception e){
Log.e("JSONError:onPostExecute",e.toString());
}
}
}
public void downLoadComplete(boolean result,FileDownLoadInfo fileInfo){
if(result){
//入库
// fileInfo.productName = fileInfo.productId + "_" + fileInfo.cfgName + "\\" + fileInfo.productName;
try{
// dbFileServer.AddOrUpdateFileDownLoadInfo(fileInfo);
showToastTips("下载完成");
}catch (Exception ex){
showToastTips("入库失败:"+ ex.toString());// doJsFunction("downloadFileSuccess('"+fth+"')");
}
}else
{
String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE};
if( permissionNoGranted(permissions,false)){
showToastTips("下载文件失败,没有权限");
}else{
showToastTips("下载文件失败");
}
}
// showToastTips("下载文件"+ result);
}
//endregion
下面是完整的X5WebviewActivity 代码
package com.example.demo;
import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.JavascriptInterface;
import android.webkit.JsPromptResult;
import android.widget.FrameLayout;
import android.widget.Toast;
import com.example.demo.db.FileDownLoadInfo;
import com.example.demo.ui.X5WebView;
import com.example.demo.utility.FileUtility;
import com.tencent.smtt.export.external.extension.interfaces.IX5WebViewExtension;
import com.tencent.smtt.export.external.interfaces.IX5WebChromeClient;
import com.tencent.smtt.export.external.interfaces.JsResult;
import com.tencent.smtt.export.external.interfaces.WebResourceError;
import com.tencent.smtt.export.external.interfaces.WebResourceRequest;
import com.tencent.smtt.sdk.CookieSyncManager;
import com.tencent.smtt.sdk.DownloadListener;
import com.tencent.smtt.sdk.ValueCallback;
import com.tencent.smtt.sdk.WebChromeClient;
import com.tencent.smtt.sdk.WebSettings;
import com.tencent.smtt.sdk.WebView;
import com.tencent.smtt.sdk.WebViewClient;
import com.tencent.smtt.utils.TbsLog;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static java.lang.System.currentTimeMillis;
public class X5WebviewActivity extends AppCompatActivity {
private X5WebView mWebView;
private ViewGroup mViewParent;
private final int hand_js_doJsFunction = 1;
private Context mContext;
private String app_downLoadPath = "";
public static List<String> downFileList = new ArrayList<String>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_x5_webview);
BindWebView();
mContext = getApplicationContext();
app_downLoadPath = getBaseDir(mContext) + "/download/";//下载到app私有目录
}
private static String getBaseDir(Context context) {
String externalStoragePublicDirectory = context.getExternalFilesDir("").getAbsolutePath();// Environment.MEDIA_MOUNTEDEnvironment.getExternalFilesDir(Environment.DIRECTORY_PICTURES).getAbsolutePath();
File dir = new File(externalStoragePublicDirectory);
if (!dir.exists()) {
dir.mkdirs();
}
return externalStoragePublicDirectory;
}
private void BindWebView(){
mViewParent = (ViewGroup) findViewById(R.id.webView1);
IniteWebView();
}
private void IniteWebView(){
mWebView = new X5WebView(this, null);
//动态添加webview
mViewParent.addView(mWebView, new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.FILL_PARENT,
FrameLayout.LayoutParams.FILL_PARENT));
//长按监听
mWebView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
return true;
}
});
WebSettings settings = mWebView.getSettings();
settings.setAllowFileAccess(true);
settings.setAllowFileAccessFromFileURLs(true);
settings.setAllowUniversalAccessFromFileURLs(true);
settings.setJavaScriptEnabled(true);
mWebView.loadUrl( "file:///android_asset/test.html");//本地文件
//mWebView.loadUrl( "www.baidu.com");//网络文件
//定义给页面js调用app的方法
mWebView.addJavascriptInterface(appToJsObject, "AndroidJS");
}
//== webview 与js交互=========================
//定义提供html页面调用的方法
public final Object appToJsObject = new Object() {
@JavascriptInterface
public void GetAppInfo() {//获取app信息
String appInfo = getAppInfo();
doJsFunction("backInfo('"+appInfo+"')");
}
@JavascriptInterface
public void downloadFile(String path,String appId,String productId,String cfgName,String productName,String imgUrl) { //文件下载
try {
String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE};
if( OpenPermissions(permissions,true)){
return;
}
FileDownLoadInfo _model = new FileDownLoadInfo(appId,cfgName,Integer.parseInt(productId),productName,imgUrl,"");
DownloadFile(_model,path);
}catch (Exception e)
{
}
}
};
//定义公共方法调用页面js方法
public void doJsFunction(String _url)
{
Message msg = new Message();
msg.what = hand_js_doJsFunction;
Bundle bundle = new Bundle();
bundle.putString("url",_url); //往Bundle中存放数据
msg.setData(bundle);//mes利用Bundle传递数据
handler.sendMessage(msg);//用activity中的handler发送消息
}
//用handler访问让方法在主进程内处理
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
String[] args = (String[]) msg.obj;
switch (msg.what) {
case hand_js_doJsFunction:
// String str1 = msg.getData().getString("url");//接受msg传递过来的参数
//调用页面js方法
mWebView.loadUrl("javascript:"+msg.getData().getString("url"));
break;
default:
break;
}
}
};
//获取应用信息
public String getAppInfo() {
String info = "";
try {
Context mContext = getApplicationContext();
PackageManager packageManager = mContext.getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(mContext.getPackageName(), 0);
info += "版本号:" + packageInfo.versionName + "\n";
info += "包 名:" + packageInfo.packageName + "\n";
} catch (Exception e) {
e.printStackTrace();
}
return info;
}
//region description== download ==function==============================================================
public void DownloadFile(FileDownLoadInfo _model,String path){
if(!downFileList.contains(path)){
new X5WebviewActivity.DownloadAsyncTas(_model).execute(path);
downFileList.add(path);
}
}
private boolean isLoad = false;
private final int FILE_SIZE = 0;
private final int DOWNLOAD_PROGRESS = 1;
private final int DOWNLOAD_START = 4;
private final int DOWNLOAD_SUCCESS = 2;
private final int DOWNLOAD_FAIL = 3;
class DownloadAsyncTas extends AsyncTask<String, Integer, Integer> {
String fileID = "";
String name = "";
String downloadPath = "";
FileDownLoadInfo fileInfo = null ;
long completeLen = -1;
String saveFilePath = "";
DownloadAsyncTas(FileDownLoadInfo _fileInfo){
fileInfo = _fileInfo;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
isLoad = true;
// setHand(hand_js_downLoadBegin);
}
@Override
protected Integer doInBackground(String... params) {
//完成下载任务
downloadPath = params[0];//这是从execute方法中传过来的参数, 即下载的地址
try {
URL url = new URL(downloadPath);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5*1000);
conn.setReadTimeout(5000);
conn.setRequestMethod("GET");
if (conn.getResponseCode() == 200) {
String file = conn.getURL().getFile();
String _express = FileUtility.getExtensionFromFilename(downloadPath);
fileInfo.productName = fileInfo.productName+ "_" + fileInfo.cfgName + "_" + fileInfo.appId + _express;;//+ "_" + fileInfo.productId
String fileName = fileInfo.productName;//file.substring(file.lastIndexOf('/')+1);
// if(!fileName.toLowerCase().endsWith(_express)){
// fileName = fileName + _express;
// }
if(fileInfo != null){//断点续传
String dir = app_downLoadPath;// + fileInfo.productId + "_" + fileInfo.cfgName + "/";
saveFilePath = dir + fileName;
FileUtility.checkPath(saveFilePath);
File info = new File(saveFilePath);
if(info.exists()){
info.delete();
}
int size = conn.getContentLength();//获取到最大值之后设置到进度条的MAX
publishProgress(FILE_SIZE, size);
//开始下载
byte[] bytes = new byte[1024];//为方便测试故将其设置较小1024
int len = -1;
InputStream in = conn.getInputStream();
boolean append = false;
if(completeLen > 0){
in.skip(completeLen);
append = true;
}
FileOutputStream out = new FileOutputStream(saveFilePath,append);
while( (len = in.read(bytes)) != -1 ){
out.write(bytes, 0, len);
completeLen += len;
publishProgress(DOWNLOAD_PROGRESS, len);
out.flush();
}
out.close();
in.close();
}else{
return DOWNLOAD_FAIL;
}
}else{
return DOWNLOAD_FAIL;
}
} catch (Exception e) {
return DOWNLOAD_FAIL;
}
return DOWNLOAD_SUCCESS;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
switch (values[0]){
case FILE_SIZE:
// _progress.setMax(values[1]);
break;
case DOWNLOAD_PROGRESS:
// _progress.incrementProgressBy(values[1]);
break;
case DOWNLOAD_START:
//_progress.setInfo(values[1], true);
break;
}
}
@Override
protected void onPostExecute(Integer integer) {
super.onPostExecute(integer);
isLoad = false;
downFileList.remove(downloadPath);
try {
if(integer == DOWNLOAD_SUCCESS){
downLoadComplete(true,fileInfo);
}else if(integer == DOWNLOAD_FAIL){
downLoadComplete(false,fileInfo);
}
}catch (Exception e){
Log.e("JSONError:onPostExecute",e.toString());
}
}
}
public void downLoadComplete(boolean result,FileDownLoadInfo fileInfo){
if(result){
//入库
// fileInfo.productName = fileInfo.productId + "_" + fileInfo.cfgName + "\\" + fileInfo.productName;
try{
// dbFileServer.AddOrUpdateFileDownLoadInfo(fileInfo);
showToastTips("下载完成");
}catch (Exception ex){
showToastTips("入库失败:"+ ex.toString());// doJsFunction("downloadFileSuccess('"+fth+"')");
}
}else
{
String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE};
if( permissionNoGranted(permissions,false)){
showToastTips("下载文件失败,没有权限");
}else{
showToastTips("下载文件失败");
}
}
// showToastTips("下载文件"+ result);
}
//endregion
public void showToastTips(String msg){
//Toast.makeText(getApplicationContext(),msg,Toast.LENGTH_LONG).show();
Toast toast = Toast.makeText(getApplicationContext(),null,Toast.LENGTH_LONG);
toast.setText(msg);
toast.show();
}
protected boolean OpenPermissions(String[] permissions ,boolean isShowTips ){
if (Build.VERSION.SDK_INT >= 23) {
int REQUEST_CODE_CONTACT = 103;
List<String> mPermissionList = new ArrayList<>();
//验证是否许可权限
for (String str : permissions) {
if (this.checkSelfPermission(str) != PackageManager.PERMISSION_GRANTED) {
//申请权限
mPermissionList.add(str);
}
}
if(mPermissionList.size() > 0){
if(isShowTips){
showToastTips("权限不足!");
}
// String[] permissions = mPermissionList.toArray(new String[mPermissionList.size()]);//将List转为数组
this.requestPermissions( mPermissionList.toArray(new String[mPermissionList.size()]), REQUEST_CODE_CONTACT);
return true;
}
}
return false;
}
//区别于 OpenPermissions 方法的是,本方法不进行权限请求;首页会进行一次权限的请求
protected boolean permissionNoGranted(String[] permissions ,boolean isShowTips ){
if (Build.VERSION.SDK_INT >= 23) {
int REQUEST_CODE_CONTACT = 103;
List<String> mPermissionList = new ArrayList<>();
//验证是否许可权限
for (String str : permissions) {
if (this.checkSelfPermission(str) != PackageManager.PERMISSION_GRANTED) {
//申请权限
mPermissionList.add(str);
}
}
if(mPermissionList.size() > 0){
if(isShowTips){
showToastTips("权限不足!");
}
return true;
}
}
return false;
}
}
FileDownLoadInfo.java
package com.example.demo.db;
public class FileDownLoadInfo {
public String appId;
public int productId;
public String cfgName;
public String productName;
public String imgUrl;
public String dateStr;
public FileDownLoadInfo(String _appId, String _cfgName, int _productId, String _productName, String _imgUrl, String _dateStr) {
super();
this.appId = _appId;
this.cfgName = _cfgName;
this.productId = _productId;
this.productName = _productName;
this.imgUrl = _imgUrl;
this.dateStr = _dateStr;
}
public FileDownLoadInfo(){
}
}
FileUtility.java
package com.example.demo.utility;
import android.content.Context;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.RandomAccessFile;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Calendar;
import android.content.res.AssetManager.AssetInputStream;
import android.os.storage.StorageManager;
import android.util.Log;
import static android.content.Context.STORAGE_SERVICE;
/**
* Created by WANG.Lei on 2018/7/6.
*/
public class FileUtility {
private static final String TAG = "FileUtility";
/**
* 获取文件流
* @param path 文件路径
* @return
*/
public static InputStream getFileStream(String path){
InputStream is = null;
try {
is = new FileInputStream(path);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return is;
}
/**
* 获取文件输出流
* @param path 文件路径
* @return
*/
public static OutputStream getOutputStream(String path){
FileOutputStream outputStream = null;
try {
outputStream = new FileOutputStream(path);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return outputStream;
}
/**
* 检查文件路径
* @param filename 文件全路径
* @return
*/
public static String checkPath(String filename){
if (filename.indexOf(".")>0)
{
File dir = new File(filename.substring(0,filename.lastIndexOf("/")));
if (!dir.exists())
dir.mkdirs();
}
else{
File file = new File(filename);
if(!file.exists())
file.mkdir();
}
return filename;
}
/**
* 创建所有目录
* @param path
*/
public static void makeDirs(String path){
File file = new File(path);
if (!file.exists()){
file.mkdirs();
}
}
/**
* 获取文件最后一次修改时间
* @param filename
* @return
*/
public static long getFileLastModifyTime(String filename){
File f = new File(filename);
if (f.exists())
return f.lastModified();
return 0;
}
/**
* 获取文件的扩展名,通过.来进行截取文件扩展名,也可以对uri方式进行截取
* @param filename 文件名
* @return
*/
public static String getExtensionFromFilename(String fileName) {
int pos = fileName.lastIndexOf('.');
if (pos==-1)
return "";
String _name = fileName.substring(pos, fileName.length());
if(_name.indexOf('?') > 0){
_name = _name.substring(0, _name.indexOf('?'));
}
return _name;
}
/**
* 删除文件
* @param filename 文件名
* @return
*/
public static boolean deleteFile(String fileName){
if(fileName==null)
return false;
boolean ret = false;
File f = new File(fileName);
if(f.exists())
ret = f.delete();
return ret;
}
/**
* 删除指定字符串开头的文件
* @param path
* @param startWithFileName
* @return
*/
public static boolean deleteFile(String path,final String startWithFileName){
String[] filelist = getFileNamelist(path, new FilenameFilter() {
@Override
public boolean accept(File dir, String filename) {
if (filename.contains(startWithFileName))
return true;
return false;
}
});
if (filelist==null)
return false;
for(String file : filelist){
deleteFile(file);
}
return true;
}
/**
* 删除目录下的所有文件,并根据mode值来判断是否删除该目录
* @param filepath
* @param mode
* @throws IOException
*/
public static boolean delDir(String filepath, boolean mode) {
if (filepath==null)
return false;
boolean bool = true;
try{
File f = new File(filepath);// 定义文件路径
if (f.exists()) {// 判断是文件还是目录
if (f.isDirectory()){
File delFile[] = f.listFiles();
int len = f.listFiles().length;
for (int j = 0; j < len; j++) {
bool = delDir(delFile[j].getAbsolutePath(),mode);
}
if (mode) {
bool = f.delete();
Log.e(TAG, "delDir filepath=" + filepath+"--mode="+mode + " result = " + bool);
}
}else{
bool = f.delete();
Log.e(TAG, "delDir filepath=" + filepath+"--mode="+mode + " result = " + bool);
}
}
}catch(Exception e){
Log.e(TAG, "",e);
}
return bool;
}
/**
* 文件是否存在
* @param file
* @return
*/
public static boolean fileIsExists(String fileName){
if (fileName==null)
return false;
File f = new File(fileName);
if(f.exists())
return true;
return false;
}
/**
* 文件拷贝
* @param src
* @param tar
* @throws IOException
*/
public static void copyFile(File src,File tar) throws IOException
{
if (src.isFile())
{
InputStream is=new FileInputStream(src);
OutputStream op=new FileOutputStream(tar);
BufferedInputStream bis=new BufferedInputStream(is);
BufferedOutputStream bos=new BufferedOutputStream(op);
byte[] bt=new byte[8192];
int len=bis.read(bt);
while(len!=-1)
{
bos.write(bt,0,len);
len = bis.read(bt);
}
bis.close();
bos.close();
}
}
/**
* 文件拷贝
* @param srcFileName
* @param tarFileName
* @throws IOException
* @throws FileNotFoundException
*/
public static void copyFile(String srcFileName,String tarFileName) throws IOException,FileNotFoundException{
if (srcFileName==null || tarFileName == null)
throw new FileNotFoundException("文件不存在");
File src = new File(srcFileName);
File tar = new File(tarFileName);
copyFile(src,tar);
}
/**
* 从assets里面拷贝文件出来
* @param context
* @param srcFilename
* @param tagetFileName
*/
public static void copyFileForAssets(Context context, String srcFilename, String tagetFileName) {
FileOutputStream outStream =null;
AssetInputStream is =null;
try {
File file = new File(tagetFileName);
if (file.exists()){
file.delete();
}
createMultPath(file.getParentFile().getAbsolutePath());
file.createNewFile();
outStream = new FileOutputStream(file);
is = (AssetInputStream) context.getAssets().open(srcFilename);
byte[] data = new byte[1024];
int count = is.read(data);
while (count != -1) {
outStream.write(data,0,count);
count = is.read(data);
}
outStream.flush();
} catch (IOException e) {
e.printStackTrace();
}finally{
try{
outStream.close();
is.close();
}catch(Exception e){
}
}
}
public static void createMultPath(String path){
StringTokenizer st=new StringTokenizer(path,"/");
String path1=st.nextToken()+"/";
String path2 =path1;
while(st.hasMoreTokens())
{
path1=st.nextToken()+"/";
path2+=path1;
File inbox = new File(path2);
if(!inbox.exists())
inbox.mkdir();
}
}
public static void createMultPath(File file){
createMultPath(file.getAbsolutePath());
}
/**
* 将Assets中的指定目录下的所有文件拷贝到指定位置
* @param context
* @param assetDir
* @param dir
*/
public static void CopyAssets(Context context, String assetDir, String dir) {
String[] files;
try {
files = context.getResources().getAssets().list(assetDir);
} catch (IOException e1) {
return;
}
File mWorkingPath = new File(dir);
// if this directory does not exists, make one.
if (!mWorkingPath.exists()) {
if (!mWorkingPath.mkdirs()) {
}
}
for (int i = 0; i < files.length; i++) {
try {
String fileName = files[i];
// we make sure file name not contains '.' to be a folder.
if (!fileName.contains(".")) {
if (0 == assetDir.length()) {
CopyAssets(context, fileName, dir + fileName + "/");
} else {
CopyAssets(context, assetDir + "/" + fileName, dir + fileName
+ "/");
}
continue;
}
File outFile = new File(mWorkingPath, fileName);
if (outFile.exists())
outFile.delete();
InputStream in = null;
if (0 != assetDir.length()) {
in = context.getAssets().open(assetDir + "/" + fileName);
} else {
in = context.getAssets().open(fileName);
}
OutputStream out = new FileOutputStream(outFile);
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 从assets里面拷贝文件出来
* @param context
* @param srcFilename
* @param tagetFileName
*/
public static AssetInputStream getAssetsFileStream(Context context,String srcFilename) {
AssetInputStream is =null;
try {
is = (AssetInputStream) context.getAssets().open(srcFilename);
} catch (IOException e) {
e.printStackTrace();
}
return is;
}
/**
* 把流写入文件
*/
public static void writeFile(InputStream in,String tagetFileName)throws IOException{
if (in==null || tagetFileName==null)
throw new FileNotFoundException("文件名为空或者内容为空!");
File file = new File(tagetFileName);
if (!file.exists())
file.createNewFile();
FileOutputStream outStream = new FileOutputStream(file);
byte[] data = new byte[1024];
int count = in.read(data);
while (count != -1) {
outStream.write(data,0,count);
count = in.read(data);
}
outStream.flush();
try{
outStream.close();
in.close();
}
catch(Exception e){
}
}
/**
* 把流写入文件
*/
public static void writeFile(InputStream in,String tagetFileName,long pos)throws IOException{
if (in==null || tagetFileName==null)
throw new FileNotFoundException("文件名为空或者内容为空!");
File file = new File(tagetFileName);
if (!file.exists())
file.createNewFile();
RandomAccessFile outStream = new RandomAccessFile(file,"rw");
outStream.seek(pos);
byte[] data = new byte[1024];
int count = in.read(data);
while (count != -1) {
outStream.write(data,0,count);
count = in.read(data);
}
try{
outStream.close();
in.close();
}
catch(Exception e){
}
}
/**
* 文件写入
* @param inputStream
* @param fileName
* @throws IOException
*/
public static void writeFile(String msg ,String fileName,String encoder) throws IOException{
if (msg==null || fileName==null)
throw new FileNotFoundException("文件名为空或者内容为空!");
File file = new File(fileName);
// if (file.isFile())
{
if (!file.exists())
file.createNewFile();
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(file),encoder);
writer.write(msg);
writer.close();
}
}
/**
* 文件写入
* @param inputStream
* @param fileName
* @throws IOException
*/
public static void writeFileUTF(String msg ,String fileName,boolean append) throws IOException{
if (fileName==null)
throw new FileNotFoundException("文件名为空或者内容为空!");
File file = new File(fileName);
if (!file.exists())
file.createNewFile();
RandomAccessFile outStream = new RandomAccessFile(file,"rw");
if (append){
long len = file.length();
outStream.seek(len);
}
outStream.writeUTF(msg);
try{
outStream.close();
}
catch(Exception e){
}
}
/**
* 写入文件,默认utf-8编码
* @param msg
* @param fileName
* @throws IOException
*/
public static void writeFile(String msg ,String fileName) throws IOException {
writeFile(msg,fileName,"utf-8");
}
/**
* 获取某一路径下的所有文件 不包含次级目录下的文件
* @param path
* @return
*/
public static File[] getFilelist(String path){
return getFilelist(path,null);
}
/**
* 获取某一路径下的所有文件 不包含次级目录下的文件
* @param path
* @param fileter
* @return
*/
public static File[] getFilelist(String path,FilenameFilter fileter){
if (!fileIsExists(path))
return null;
File file = new File(path);
if (fileter==null)
return file.listFiles();
else
return file.listFiles(fileter);
}
/**
* 获取某一路径下的所有文件 不包含次级目录下的文件
* @param path
* @return
*/
public static String[] getFileNamelist(String path){
return getFileNamelist(path,null);
}
/**
* 获取某一路径下的所有文件 不包含次级目录下的文件
* @param path
* @param fileter
* @return
*/
public static String[] getFileNamelist(String path,FilenameFilter fileter){
if (!fileIsExists(path))
return null;
File file = new File(path);
if (fileter==null)
return file.list();
else
return file.list(fileter);
}
/**
* 获取文件的编码
* @param path
* @return
* @throws IOException
*/
public static String getFileEncoder(String path) throws IOException{
File file = new File(path);
String defaultcode= get_charset(file);
return defaultcode;
}
static String get_charset(File file) {
String charset = "GBK";
byte[] first3Bytes = new byte[3];
try {
boolean checked = false;
BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(file));
bis.mark(0);
int read = bis.read(first3Bytes, 0, 3);
if (read == -1)
return charset;
if (first3Bytes[0] == (byte) 0xFF && first3Bytes[1] == (byte) 0xFE) {
charset = "UTF-16LE";
checked = true;
} else if (first3Bytes[0] == (byte) 0xFE
&& first3Bytes[1] == (byte) 0xFF) {
charset = "UTF-16BE";
checked = true;
} else if (first3Bytes[0] == (byte) 0xEF
&& first3Bytes[1] == (byte) 0xBB
&& first3Bytes[2] == (byte) 0xBF) {
charset = "UTF-8";
checked = true;
}
//bis.reset();
if (!checked) {
int loc = 0;
while ((read = bis.read()) != -1) {
loc++;
if (read >= 0xF0)
break;
if (0x80 <= read && read <= 0xBF) // 单独出现BF以下的,也算是GBK
break;
if (0xC0 <= read && read <= 0xDF) {
read = bis.read();
if (0x80 <= read && read <= 0xBF)// 双字节 (0xC0 - 0xDF)
// (0x80 -
// 0xBF),也可能在GB编码内
continue;
else
break;
} else if (0xE0 <= read && read <= 0xEF) {// 也有可能出错,但是几率较小
read = bis.read();
if (0x80 <= read && read <= 0xBF) {
read = bis.read();
if (0x80 <= read && read <= 0xBF) {
charset = "UTF-8";
break;
} else
break;
} else
break;
}
}
}
bis.close();
} catch (Exception e) {
e.printStackTrace();
}
return charset;
}
/**
* 读取文件返回String 将文件转换为String,自动识别编码,但不准确
* @param filepath
* @return
*/
public static String readStringfromFile(String filepath){
// String content = "";
File file=new File(filepath);
StringBuilder sb=new StringBuilder();
if(file.exists()){
try {
String charset = getFileEncoder(file.getAbsolutePath());
BufferedReader reader=new BufferedReader(new InputStreamReader(new FileInputStream(file.getAbsoluteFile()),charset));
String str="";
while((str=reader.readLine())!=null){
sb.append(str);
sb.append("\n");
}
// content=sb.toString();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// content=sb.toString();
}
return sb.toString();
}
/**
* 读取一个字符串
* @param filepath
* @param encoder
* @return
*/
public static String readStringfromFile(String filepath,String encoder){
// String content = "";
File file=new File(filepath);
StringBuilder sb=new StringBuilder();
if(file.exists()){
try {
// String charset = getFileEncoder(file.getAbsolutePath());
BufferedReader reader=new BufferedReader(new InputStreamReader(new FileInputStream(file.getAbsoluteFile()),encoder));
String str="";
while((str=reader.readLine())!=null){
sb.append(str);
sb.append("\n");
}
// content=sb.toString();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// content=sb.toString();
}
return sb.toString();
}
/**
* 读取一个字符串
* @param filepath
* @param encoder
* @return
*/
public static String readStringfromFile(InputStream inputStream,String encoder){
// String content = "";
StringBuilder sb=new StringBuilder();
try {
BufferedReader reader=new BufferedReader(new InputStreamReader(inputStream,encoder));
String str="";
while((str=reader.readLine())!=null){
sb.append(str);
sb.append("\n");
}
// content=sb.toString();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// content=sb.toString();
return sb.toString();
}
/**
* 将多个文本文件合并一起
* @param files
* @param destFullName
*/
public static void FilesJoin(String[] files,String destFullName){
BufferedWriter writer;
try {
File f=new File(destFullName);
if(!f.exists())
{
f.createNewFile();
}
writer = new BufferedWriter(new FileWriter(destFullName));
for(String file:files){
String content = readStringfromFile(file);
writer.append(content);
}
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**写入结构数据**/
public static void WriteStructToFile(String fileName,int value){
if (fileName==null)
return;
OutputStream fos = getOutputStream(fileName);
DataOutputStream dos = new DataOutputStream(fos);
try {
dos.writeInt(value);
} catch (IOException e) {
e.printStackTrace();
}catch (NullPointerException e){
e.printStackTrace();
}finally {
// 在finally中关闭流 这样即使try中有异常我们也能对其进行关闭操作 ;
try {
dos.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}catch (NullPointerException e){
e.printStackTrace();
}
}
}
/**读取结构数据**/
public static int ReadStructFromFile(String fileName){
if (fileName==null || !fileIsExists(fileName))
return 0;
InputStream is = getFileStream(fileName);
DataInputStream dis = new DataInputStream(is);
int result = 0;
try {
result = dis.readInt();
} catch (IOException e) {
e.printStackTrace();
} catch (NullPointerException e){
e.printStackTrace();
}finally {
// 在finally中关闭流 这样即使try中有异常我们也能对其进行关闭操作 ;
try {
dis.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
} catch (NullPointerException e){
e.printStackTrace();
}
}
return result;
}
/**
* 返回文件长度
*/
public static long getFileSize(String fileName){
if (fileName==null)
return 0;
File file = new File(fileName);
if (!file.exists())
return 0;
return file.length();
}
public static String getFileSizeKB(String fileName){
long size = getFileSize(fileName);
double kbsize = size*1.0/1024.0;
return ((int)(kbsize*100)/100.0)+"KB";
}
public static String getFileSizeMB(String fileName){
long size = getFileSize(fileName);
double mbsize = size*1.0/1024.0/1024.0;
return ((int)(mbsize*100)/100.0)+"MB";
}
/**
* 获取文件
* 可以根据正则表达式查找
* @param dir String 文件夹名称
* @param s String 查找文件名,可带*.?进行模糊查询
* @return File[] 找到的文件
*/
public static File[] getFiles(String dir,String s) {
//开始的文件夹
File file = new File(dir);
s = s.replace('.', '#');
s = s.replaceAll("#", "\\\\.");
s = s.replace('*', '#');
s = s.replaceAll("#", ".*");
s = s.replace('?', '#');
s = s.replaceAll("#", ".?");
s = "^" + s + "$";
System.out.println(s);
Pattern p = Pattern.compile(s);
ArrayList list = filePattern(file, p);
File[] rtn = new File[list.size()];
list.toArray(rtn);
return rtn;
}
/**
* @param file File 起始文件夹
* @param p Pattern 匹配类型
* @return ArrayList 其文件夹下的文件夹
*/
private static ArrayList filePattern(File file, Pattern p) {
if (file == null) {
return null;
}
else if (file.isFile()) {
Matcher fMatcher = p.matcher(file.getName());
if (fMatcher.matches()) {
ArrayList list = new ArrayList();
list.add(file);
return list;
}
}
else if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null && files.length > 0) {
ArrayList list = new ArrayList();
for (int i = 0; i < files.length; i++) {
ArrayList rlist = filePattern(files[i], p);
if (rlist != null) {
list.addAll(rlist);
}
}
return list;
}
}
return null;
}
// public static void WriteStructToFile(String fileName,Object...args){
// if (fileName==null || !fileIsExists(fileName))
// return;
// OutputStream fos = getOutputStream(fileName);
// DataOutputStream dos = new DataOutputStream(fos);
// int len = args.length;
// try{
// for(int i=0;i<len;i++){
// if (args[i] instanceof String){
// dos.writeUTF(args[i].toString());
// }else if (args[i] instanceof Integer){
// dos.writeInt(Integer.parseInt(args[i].toString()));
// }
// }
// }catch(Exception e){
//
// }
// }
public static String getPrimaryStoragePath( Context context) {
try {
StorageManager sm = (StorageManager) context. getSystemService(STORAGE_SERVICE);
Method getVolumePathsMethod = StorageManager.class.getMethod("getVolumePaths", new Class[0]);
String[] paths = (String[]) getVolumePathsMethod.invoke(sm, new Object());
// first element in paths[] is primary storage path
return paths[0];
} catch (Exception e) {
Log.e(TAG, "getPrimaryStoragePath() failed", e);
}
return null;
}
// 获取次存储卡路径,一般就是外置 TF 卡了. 不过也有可能是 USB OTG 设备...
// 其实只要判断第二章卡在挂载状态,就可以用了.
public static String getSecondaryStoragePath(Context context) {
try {
StorageManager sm = (StorageManager)context. getSystemService(STORAGE_SERVICE);
Method getVolumePathsMethod = StorageManager.class.getMethod("getVolumePaths", new Class[] {String.class});
String[] paths = (String[]) getVolumePathsMethod.invoke(sm, new Object());
// second element in paths[] is secondary storage path
return paths.length <= 1 ? null : paths[1];
} catch (Exception e) {
Log.e(TAG, "getSecondaryStoragePath() failed", e);
}
return null;
}
// 获取存储卡的挂载状态. path 参数传入上两个方法得到的路径
public static String getStorageState(String path,Context context) {
try {
StorageManager sm = (StorageManager)context. getSystemService(STORAGE_SERVICE);
Method getVolumeStateMethod = StorageManager.class.getMethod("getVolumeState", new Class[] {String.class});
String state = (String) getVolumeStateMethod.invoke(sm, path);
return state;
} catch (Exception e) {
Log.e(TAG, "getStorageState() failed", e);
}
return null;
}
public static String getSDCardPath(Context context){
String SDCardPath = getSecondaryStoragePath(context);
if (SDCardPath != null && SDCardPath.length() > 0) {
File file = new File(SDCardPath);
if (file.exists() && file.isDirectory())
return SDCardPath;
}
return null;
}
public static boolean isZipFile(File file)
{
String fileName = file.getName().toLowerCase();
return fileName.endsWith("zip") || fileName.endsWith("rar");
}
}
最后页面js调用
function downloadFile(){
//downloadFile(String path,String appId,String productId,String cfgName,String productName,String imgUrl)
var _info = window.AndroidJS.downloadFile("https://www.runoob.com/try/demo_source/Sansation_Light.ttf","1","1","demo","Sansation_Light","");
}
另外因为下载需要请求网络权限,所以要AndroidManifest.xml 声明下权限。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.demo">
<!-- x5webview begin -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- x5webview end -->
<application
android:name=".APPAplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Demo">
<activity android:name=".X5WebviewActivity"></activity>
<activity android:name=".ViewActivity" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
demo里的依赖build.gradle
plugins {
id 'com.android.application'
}
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "com.example.demo"
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
sourceSets {
main {
assets {
srcDirs 'src\\main\\assets'
}
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation files('libs/tbs_sdk_thirdapp_v3.6.0.1249_43610_sharewithdownload_withoutGame_obfs_20180608_114954.jar')
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.google.android.material:material:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.google.code.gson:gson:2.8.5'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
demo 下载 ,该demo包含了sqlite数据记录下载记录功能