Android实现APK下载安装

来源:互联网 发布:桥梁bim软件 编辑:程序博客网 时间:2024/05/17 21:26
网上有很多种写法,也有很多坑,当然这些坑不是说代码有问题,而是Android的碎片化和各个厂商的定制造成的,例如最简单的写法DownloadManager在三星等手机上无法使用,原因是他们不支持DownloadManager。使用Thread或者IntentService或者AnsyTask其实也都可以,各有优劣。例如使用IntentService的更新UI问题,使用AnsyTask的排队问题,等等还是要看具体的需求选择最合适的实现方法。另一个问题是Android版本的问题,主要是7.0的兼容问题,不然以前的写法是要奔溃的;

兼容7.0的第一步:

在Manfist清单文件中声明一个内容提供器,当然是在Application节点内部;
<provider            android:name="android.support.v4.content.FileProvider"            android:authorities="${applicationId}.fileprovider"            android:exported="false"            android:grantUriPermissions="true">            <meta-data                android:name="android.support.FILE_PROVIDER_PATHS"                android:resource="@xml/provider_paths"/>        </provider>

这里的applicationId占位其实是buildgradle文件中applicationId,也就是项目的包名,可以直接用项目包名代替。
而这个文件@xml/provider_paths是不存在的,是需要在res下新建的;
这里写图片描述

接下来给出一个provider_paths.xml的范例:

<?xml version="1.0" encoding="utf-8"?><paths>    <external-path path="Android/data/自己的项目包名/" name="files_root" />    <external-path path="." name="external_storage_root" /></paths>

最后是android调用Apk安装:

public void installApkFile( String filePath) {        //Log.e("JACK",filePath);        Intent intent = new Intent(Intent.ACTION_VIEW);        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {            intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);            Uri contentUri = FileProvider.getUriForFile(mContext, "com.caihongto.caihongtoforcustomer.fileprovider", new File(filePath));            intent.setDataAndType(contentUri, "application/vnd.android.package-archive");        } else {            intent.setDataAndType(Uri.fromFile(new File(filePath)), "application/vnd.android.package-archive");            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);        }        mContext.startActivity(intent);    }

有一点需要注意的是:
这里写图片描述

这里的命名必须和清单文件的命名一致;

下面是下载与安装代码:

public class DownloadAsyncTask extends AsyncTask<String, Integer, Boolean> {    private Context mContext;    int per = 0;    private ProgressDialog perDialog = null;    private String fullPath = null;    //private File apkFile;    public  DownloadAsyncTask(Context context){        mContext=context;    }    @Override    protected Boolean doInBackground(String... params) {        fullPath = params[1] + params[2];        try {            URL url = new URL(params[0]);            HttpURLConnection huc = (HttpURLConnection) url                    .openConnection();            huc.setConnectTimeout(10 * 1000);            huc.connect();            if (huc.getResponseCode() == 200) {                perDialog.setMax(huc.getContentLength());                File path = new File(params[1]);                if (!path.exists()) {                    path.mkdirs();                }                File apkFile = new File(path, params[2]);                if (!apkFile.exists()) {                    apkFile.createNewFile();                }                InputStream is = huc.getInputStream();                FileOutputStream fos = new FileOutputStream(apkFile);                byte[] buf = new byte[1024];                int readSize;                while (true) {                    readSize = is.read(buf);                    if (readSize <= 0) {                        break;                    }                    per += readSize;                    this.publishProgress(per);                    fos.write(buf, 0, readSize);                }                fos.close();                is.close();                return true;            } else {                return false;            }        } catch (MalformedURLException e) {            return false;        } catch (IOException e) {            return false;        }    }    @Override    protected void onPostExecute(Boolean result) {        super.onPostExecute(result);        perDialog.dismiss();        if (result) {            Toast.makeText(mContext, "下载完成", Toast.LENGTH_SHORT)                    .show();            installApkFile(fullPath);        } else {            Toast.makeText(mContext, "下载失败", Toast.LENGTH_SHORT)                    .show();        }    }    @Override    protected void onPreExecute() {        super.onPreExecute();        perDialog = new ProgressDialog(mContext);        perDialog.setMessage("正在下载...");        perDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);// 设置水平进度条        perDialog.setCancelable(true);// 设置是否可以通过点击Back键取消        perDialog.setCanceledOnTouchOutside(false);// 设置在点击Dialog外是否取消Dialog进度条        perDialog.show();    }    @Override    protected void onProgressUpdate(Integer... values) {        super.onProgressUpdate(values);        perDialog.setProgress(values[0]);    }    public void installApkFile( String filePath) {        Intent intent = new Intent(Intent.ACTION_VIEW);        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {            intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);            Uri contentUri = FileProvider.getUriForFile(mContext,                    "com.caihongto.caihongtoforcustomer.fileprovider",                    new File(filePath));            intent.setDataAndType(contentUri, "application/vnd.android.package-archive");        } else {            intent.setDataAndType(Uri.fromFile(new File(filePath)), "application/vnd.android.package-archive");            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);        }        mContext.startActivity(intent);    }}

最后看下怎么调用的吧;

String[] params = new String[] { "http://www.caihongto.com/public/androidapk/6cc043563be7528213bbfa585245a5f9.apk",Environment.getExternalStorageDirectory() + "/pistol/app/", "caihongto_.apk" };        new DownloadAsyncTask(MainActivity.this).execute(params);

就这样吧,如果有什么同类的问题,大家可以留言;


另外附上一种大神的写法:

首先定义一个将Apk的存储File 转换为Uri的方法,代码如下:

 public static Uri getFileExternalContentUri(Context context, File externalFile) {        String filePath = externalFile.getAbsolutePath();        Cursor cursor = context.getContentResolver().query(MediaStore.Files.getContentUri("external"),                new String[]{MediaStore.Files.FileColumns._ID},                MediaStore.Files.FileColumns.DATA + "=? ",                new String[]{filePath}, null);        if (cursor != null && cursor.moveToFirst()) {            int id = cursor.getInt(cursor.getColumnIndex(MediaStore.Files.FileColumns._ID));            cursor.close();            return Uri.withAppendedPath(MediaStore.Files.getContentUri("external"), "" + id);        } else {            if (externalFile.exists()) {                ContentValues values = new ContentValues();                values.put(MediaStore.Files.FileColumns.DATA, filePath);                return context.getContentResolver().insert(MediaStore.Files.getContentUri("external"), values);            } else {                return null;            }        }    }

然后在完成下载之后调用这个方法,并实现安装逻辑:

 public static boolean installApp(File apkFile, final Context context) {        LogUtil.i(TAG, "开始安装apk 文件包:");        if (apkFile != null && apkFile.exists() && apkFile.isFile()) {            if (context != null) {                // 通过Intent安装APK文件                final Intent instalInstant = new Intent(Intent.ACTION_VIEW);                instalInstant.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {                    instalInstant.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);                    instalInstant.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);                    Uri apkFileURI = ResUtil.getFileExternalContentUri(context,apkFile);                    instalInstant.setDataAndType(apkFileURI, "application/vnd.android.package-archive");                    if (context != null) {                        context.startActivity(instalInstant);                    }                } else {                    instalInstant.setDataAndType(Uri.parse("file://" + apkFile.getAbsolutePath()), "application/vnd.android.package-archive");                }                return true;            } else {                LogUtil.e(TAG, "installApp() --> context  is null  !!! ");            }        } else {            LogUtil.e(TAG, "installApp() --> apkFile  exists =  false !!! ");        }        return false;    }

先这样吧

1 0