Android开发 - 下载网络文件到本地

<上一篇  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数据记录下载记录功能

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值