复习一下APK内部升级

注:本篇文章参考自源项目,接手之前部分代码就有了,只不过在Android高版本上不能安装APK,还有部分逻辑未完善,如果有原创哥们不经意间看到这篇文章,可以评论一下原文地址,我下次看到了标注好,无意冒犯。

 

一、引言

  • 当前Android系统在国内已经非常成熟,各大厂更新机制各有千秋,当下比较出名的热更新、插件化、迭代升级,甚至还有最近国内N多某某小动作片还用了大量的H5嵌套,便于页面动态切换。关于热更新、插件化这方面就不多说了,感兴趣的朋友可以在网上看看,大厂框架比较多也比较成熟。近一年应公司业务一直在写SDK,里面用到了大量的插件化、动态加载、HOOK技术,年底忙完抽空写一篇文章详细解读,可以关注一下。

  • 其实APK迭代升级这种方式比较常见,只是如果APK已经上传了应用市场,经常进行APK迭代对用户来说比较反感,所以大型应用一般都是热更新为主,除非大改动、大更新才会进行迭代升级。

  • APK迭代一般分为自己平台上传APK,自行升级;还有一种就是应用市场升级,应用市场升级基本就交给市场;这篇文章主要讲一下APK内部升级,方便大伙借鉴。

二、实现步骤

  • 请求服务器获取服务器上版本信息,与本地对比决定是否升级,当然代码自己写,强不强制看需求。我这里用的是 versionCode 字段,因为这个是整数,判断起来方便。以下是获取的字段信息。
        {
            "apk_name":"app_Name",
            "apk_version":"1.0.0",
            "apk_code":2,
            "isUpdata":0,
            "download":"http://qn.yingyonghui.com/apk/6741348/de3d5ab.apk",
            "data":[
                {
                    "code":"新增功能暗黑模式"
                },
                {
                    "code":"优化部分BUG"
                }
            ]
        }
  • 然后进行Code对比,网络请求这块我使用的是okhttp,
 Request request=new Request.Builder().url(QUEST_URL).build();
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if(response.code() == 200){
                    String content = response.body().string();
                    if(!TextUtils.isEmpty(content)){
                        try {
                            JSONObject jsonObject = new JSONObject(content);
                            int isUpdata = JsonUtils.getInt(jsonObject, "isUpdata");    // 是否强制升级  0,不强制,1,强制升级
                            int apk_code = JsonUtils.getInt(jsonObject, "apk_code");    // 应用版本号
                            String download = JsonUtils.getString(jsonObject, "download");  // apk下载地址
                            JSONArray array = JsonUtils.getJSONArray(jsonObject,"data");    // 升级内容
                            if(apk_code > Utils.getVersionCode(mainActivity)){
                                upDataApk(mainActivity,isUpdata,download,array);
                            } else {
                                if(isTos){
                                    mainActivity.runOnUiThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            Toast.makeText(mainActivity,"当前已经是最新版本了",Toast.LENGTH_SHORT).show();
                                        }
                                    });
                                }
                            }
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
  • 下载APK文件

    Request request=new Request.Builder().url(url).build();
            okHttpClient.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    int lenght=0;
                    byte[] buf=new byte[2048];
                    InputStream inputStream=null;
                    FileOutputStream fileOutputStream=null;
                    File f = null;
                    try {
                        //存储下载文件目录
                        String sd = SDCardUtils.getExternalSdCardPath();
                        if (!TextUtils.isEmpty(sd)) {
                            f = new File(downPath);
                            if (!f.exists()) {
                                boolean externalDirSuccess = f.mkdirs();
                                if (!externalDirSuccess){
                                    f = new File(context.getDir("cachedata", 0) + File.separator);
                                    if (!f.exists()) {
                                        boolean internalDirSuccess = f.mkdirs();
                                        if (!internalDirSuccess){
                                            f = new File(context
                                                    .getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
                                                    .getAbsolutePath()+File.separator);
                                            if (!f.exists()){
                                                boolean dirSuccess = f.mkdir();
                                                if (!dirSuccess){
                                                    listener.onDownloadFailed();
                                                    return;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        inputStream = response.body().byteStream();
                        long total = response.body().contentLength();
                        File file = new File(f.getAbsoluteFile(), getNameFromUrl(url));
                        if(file.exists()) {
                            file.delete();
                        }
                        file.getParentFile().mkdirs();
                        getRoot("chmod -R 777 "+file.getAbsolutePath());
                        fileOutputStream = new FileOutputStream(file);
                        long sum = 0;
                        while ((lenght = inputStream.read(buf)) != -1) {
                            fileOutputStream.write(buf,0,lenght);
                            sum+=lenght;
                            int progress=(int)(sum*1.0f/total*100);
                            listener.onDownloading(progress);
                        }
                        fileOutputStream.flush();
                        listener.onDownloadSuccess(file);
                    }catch (Exception e){
                        listener.onDownloadFailed();
                    }finally {
                        try {
                            if (inputStream != null)
                                inputStream.close();
                            if (fileOutputStream != null)
                                fileOutputStream.close();
                        }catch (Exception e){
                        }
                    }
                    AppLogger.e(TAG+"onResponse 2");
                }
            });

  • 接下来就是APK安装了

                        
                        try{
                            String provide = "com.mars.mxbrowser.fileprovider";
                            Uri contentUri = FileProvider.getUriForFile(mainActivity.getApplicationContext(), provide, file);
                            Intent intent = new Intent(Intent.ACTION_VIEW);
                            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                            intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
                            //写的时候没有权限  所以加上权限
                            String[] command = {"chmod", "777", file.getAbsolutePath() };
                            ProcessBuilder builder = new ProcessBuilder(command);
                            try {
                                builder.start();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                            mainActivity.startActivity(intent);
                            dialog.dismiss();
                        }catch (Throwable e){
                            e.printStackTrace();
                        }

  • 上面安装这里之前是有点问题的,因为高版本上安装需要配置provider,provider是在AndroidManifest.xml,</application>标签下面进行配置,我测试手机是10.0的。以下是provider的配置,这里要主要一下:所配置的authorities一定要和上面安装APK打开器配置的provide一致,否则会报错;还有一些开发人员android:name时配置找不到,比如在一些低版本上,这里我选用的是androidx.core.content.FileProvider,属于androidx,在gradle下配置一下就行了。
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/bd_file_paths" />
        </provider>
  • 到这里就结束了,打开APK安装器后会弹出应用安装页面,取决于用户会不会去安装,一般应用升级的是用户自己点的,应该是没什么疑问的。我们做SDK时,很多时候都是静默下载安装,用户都比较懵逼,当然高版本上也有限制,也需要用户自己安装。需要Demo代码的可以留言邮箱。

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值