下载自动安装apk(android10)

首先是下载的时候,文件下不下来,加了权限也不行。
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

需要在AndroidManifest中配置一下
<application
...
android:requestLegacyExternalStorage="true" // 这样就可以采用原有的存储策略

参考:https://blog.csdn.net/hgy413/article/details/105902424?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2allsobaiduend~default-3-105902424.nonecase&utm_term=android%E6%B2%A1%E6%9D%83%E9%99%90%E5%88%9B%E5%BB%BA%E6%96%87%E4%BB%B6&spm=1000.2123.3001.4430

下载后就是打开apk文件,7.0以上加上FileProvider和file_paths.xml。

但是依然打不开apk文件。

此时需要加一个权限<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>

参考:https://blog.csdn.net/chxc_yy/article/details/81536875

注意,若代码里已经有了FileProvider和file_paths.xml,比喻,下载图片时也需要。
此时需要重新为下载apk再来自定义一个FileProvider
注意android:authorities和android:resource要不一样,区分开
参考:https://www.pianshen.com/article/7748702374/

<provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="包名.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

        <provider
            android:name="包名.utils.MyFileProvider"
            android:authorities="包名.download.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/download_file_paths" />
        </provider>

附上下载安装代码:

/**
 * 版本控制
 */
@SuppressWarnings("ALL")
public class VersionUpdateHelper {
    public static final String TAG = VersionUpdateHelper.class.getSimpleName();

    private static final int UPDATE_NOTIFICATION_PROGRESS = 0x1;
    private static final int COMPLETE_DOWNLOAD_APK = 0x2;
    private static final int DOWNLOAD_NOTIFICATION_ID = 0x3;
    private static final int FAILED_DOWNLOAD_APK = 0x4;
    private static final String CURRENT_TIME = "current_time";
    private static final String VERSION_CODE = "version_code";

    private Context mContext;
    private NotificationManager notificationManager;
    private NotificationCompat.Builder ntfBuilder;
    private static String sPath;
    private static final String SUFFIX = ".apk";//下载完成后的文件名后缀
    private static final String APP_NAME = "APP_NAME";//app名

    private HashMap<String, String> cache = new HashMap<String, String>();//存放路径名和app的名字

    private boolean isAutoInstall;//是否自动安装

    private static final int PUSH_NOTIFICATION_ID = (0x001);
    private static final String PUSH_CHANNEL_ID = "NOTIFY_ID";
    private static final String PUSH_CHANNEL_NAME = "PUSH_NOTIFY_NAME";

    ProgressDialog pd;    //进度条对话框

    public VersionUpdateHelper(Context mContext, boolean isAutoInstall) {
        this.mContext = mContext;
        this.isAutoInstall = isAutoInstall;
        getApkPath(mContext);
    }

    public static String getApkPath(Context context) {
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            sPath = Environment.getExternalStorageDirectory().getAbsolutePath();
        } else {
            SDCardUtils.StorageList storageList = new SDCardUtils.StorageList(context);
            sPath = storageList.getVolumePaths()[1];
        }
        return sPath + File.separator + context.getString(R.string.app_name)
                + File.separator + context.getString(R.string.app_name)
                + SUFFIX;
    }


    private Handler handler = new DownloadHandler();


    public void loadVersion(Context mContext,String downloadURL) {
        downloadApk(mContext,downloadURL);
    }


    /**
     * 下载apk
     *
     * @param url apkUrl
     */
    private void downloadApk(Context mContex, String url) {
        pd = new ProgressDialog(mContex);
        pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        pd.setMessage("正在下载...");
        pd.show();
        pd.setCancelable(false);

        Log.e("downloadApk", url);
        AsyncDownLoad asyncDownLoad = new AsyncDownLoad();
        asyncDownLoad.execute(url);
    }

    /**
     * 异步下载app任务
     */
    private class AsyncDownLoad extends AsyncTask<String, Integer, Boolean> {
        @Override
        protected Boolean doInBackground(String... params) {
            try {

                URL url = new URL(params[0]);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(10000);  // 连接超时时间 毫秒级 10S
                conn.setReadTimeout(10000); //读取超时时间
                conn.setRequestMethod("GET"); //请求方式
                conn.setDoInput(true); //打开输入流
                conn.connect(); //获取连接
                long beforeTime = System.currentTimeMillis();

                pd.setProgressNumberFormat("%1d M/%2d M");
                pd.setMax((int)conn.getContentLength()/1024/1024);

                if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                    //获得网络字节输入流对象
                    InputStream is = conn.getInputStream();
                    long total = conn.getContentLength();
                    String apkName = mContext.getString(R.string.app_name)
                            + SUFFIX;
                    cache.put(APP_NAME, mContext.getString(R.string.app_name));
                    File savePath = new File(sPath + File.separator
                            + mContext.getString(R.string.app_name));
                    if (!savePath.exists())
                        savePath.mkdirs();
                    File apkFile = new File(savePath, apkName);
                    //如果文件已经存在,或者已经下载完成了,就不做下载操作
                    Log.v("ver","apkFile.exists()=="+apkFile.exists());
                    /*if (apkFile.exists() && apkFile.length() == total) {
                        return true;
                    }*/
                    FileOutputStream fos = null;
                    fos = new FileOutputStream(apkFile);
                    byte[] buf = new byte[1024];
                    int count = 0;
                    int length = -1;
                    while ((length = is.read(buf)) != -1) {
                        fos.write(buf, 0, length);
                        count += length;

                        pd.setProgress((int)count/1024/1024);

                    }
                    is.close();
                    fos.close();
                    return true;
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return false;
        }

        @Override
        protected void onPostExecute(Boolean flag) {
            pd.dismiss(); //结束掉进度条对话框
            if (flag) {
                handler.obtainMessage(COMPLETE_DOWNLOAD_APK).sendToTarget();
            } else {
                Log.e("Error", "下载失败。");
            }
        }
    }


    /**
     * 安装APK
     *
     * @param data
     */
    private void installApk(File file) {
        if (mContext != null) {

            if(Build.VERSION.SDK_INT>=24) {//判读版本是否在7.0以上
                Uri apkUri = MyFileProvider.getUriForFile(mContext, "包名.download.fileprovider", file);
                Intent install = new Intent(Intent.ACTION_VIEW);
                install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//添加这一句表示对目标应用临时授权该Uri所代表的文件
                install.setDataAndType(apkUri, "application/vnd.android.package-archive");
                mContext.startActivity(install);

                if (notificationManager != null) {
                    notificationManager.cancel(DOWNLOAD_NOTIFICATION_ID);
                }
            }else {

                Intent i = new Intent(Intent.ACTION_VIEW);
                i.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
                i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                mContext.startActivity(i);
                if (notificationManager != null) {
                    notificationManager.cancel(DOWNLOAD_NOTIFICATION_ID);
                }
            }

        } else {
            Log.e("NullPointerException", "The context must not be null.");
        }
    }

    //负责接收进度以及下载完成后启动安装的activity
    @SuppressLint("HandlerLeak")
    private class DownloadHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case COMPLETE_DOWNLOAD_APK:
                    if (isAutoInstall) {
                        installApk(new File(getApkPath(mContext)));
                    } else {
                        if (ntfBuilder == null) {
                            ntfBuilder = new NotificationCompat.Builder(mContext);
                        }
                        ntfBuilder.setSmallIcon(mContext.getApplicationInfo().icon)
                                .setContentTitle(mContext.getString(R.string.app_name))
                                .setContentText("下载完成,点击安装").setTicker("任务下载完成");
                        Intent intent = new Intent(Intent.ACTION_VIEW);
                        intent.setDataAndType(
                                Uri.parse("file://" + getApkPath(mContext)),
                                "application/vnd.android.package-archive");
                        PendingIntent pendingIntent = PendingIntent.getActivity(
                                mContext, 0, intent, 0);
                        ntfBuilder.setContentIntent(pendingIntent);
                        if (notificationManager == null) {
                            notificationManager = (NotificationManager) mContext
                                    .getSystemService(Context.NOTIFICATION_SERVICE);
                        }
                        notificationManager.notify(DOWNLOAD_NOTIFICATION_ID,
                                ntfBuilder.build());
                    }
                    break;
                case FAILED_DOWNLOAD_APK:
                    if (ntfBuilder == null) {
                        ntfBuilder = new NotificationCompat.Builder(mContext);
                    }
                    ntfBuilder.setSmallIcon(mContext.getApplicationInfo().icon)
                            .setContentTitle(mContext.getString(R.string.app_name))
                            .setContentText("下载失败,请检查网络").setTicker("新版本下载失败");
                    notificationManager.notify(DOWNLOAD_NOTIFICATION_ID,
                            ntfBuilder.build());
                    break;
            }
        }

    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,367评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,959评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,750评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,226评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,252评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,975评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,592评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,497评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,027评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,147评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,274评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,953评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,623评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,143评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,260评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,607评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,271评论 2 358

推荐阅读更多精彩内容