前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自定义Androidk全量更新组件

自定义Androidk全量更新组件

作者头像
饮水思源为名
发布2018-09-06 13:01:02
1.2K0
发布2018-09-06 13:01:02
举报
文章被收录于专栏:Android小菜鸡

自动更新功能对于一个APP来说是必备的功能,特别是对于未投放市场下载的APP,每次都让用户删掉原来的,再下载新的版本,肯定是不合适的。

实现思路:

  1. 后台提供接口,返回服务端版本号serviceVersion以及APK下载地址
  2. 前端对接接口,用拿到的serviceVersion和APK配置的localVersion比较,如果serviceVersion>localVersion则提示可以更新,通过获取的APK下载地址下载,然后通过api打开安装完成更新。

注意:

  1. localVersion笔者使用的是versionCode,可以再AndroidManifest中配置,通过java代码获取。笔者与后台约定了Code的规则,采用更新时间编辑,例如2018年8月2号,则versionCode=“180802”
代码语言:javascript
复制
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.mintu.dcdb"
    android:versionCode="180802"
    android:versionName="3.6">
代码语言:javascript
复制
  /**
     * 获取当前本地apk的版本号
     * @param mContext
     * @return
     */
    public static int getVersionCode(Context mContext) {
        int versionCode = 0;
        try {
            //获取软件版本号,对应AndroidManifest.xml下android:versionCode
            versionCode = mContext.getPackageManager().
                    getPackageInfo(mContext.getPackageName(), 0).versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return versionCode;
    }
  1. 对于Android7.0以上的手机,打开附件做了改变,无法使用以往的uri发布意图,详情可见笔者之前的一篇文章。Android7.0以上版本打开附件失败问题
  2. 本文的文件下载、附件打开方法使用的是笔者封装的OkHttp3工具类,使用者可以自己随意替换。只要将APK从url上下载下来,用API打开即可。

核心代码:

代码语言:javascript
复制
     /***
     * 检查是否更新版本
     */
    private void checkVersion() {
        if (Integer.parseInt((String) sharedPreferencesUtil.getData(Constant.VERSION_CODE_LOCAL,"")) < Integer
                .parseInt(CommonUtil.getInstance().isNull(sharedPreferencesUtil.getData(Constant.VERSION_CODE,"")) ? "0"
                        : (String) sharedPreferencesUtil.getData(Constant.VERSION_CODE,""))) {
            showDialog(new DownLoadBroadCastReceiver());
        }else{
            if(!isAutoUpdate) Toast.makeText(activity, "未检查到新版本", Toast.LENGTH_SHORT).show();
        }
    }  
代码语言:javascript
复制
    /***
     * 开线程下载
     */
    public void createThread(final String downUrl) {
        final Message message = new Message();
        if (SystemUtils.isNetworkAvailable(getApplicationContext())) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        OkHttpUtil.getInstance().download(downUrl, newApkUrl, file_name, new OkHttpUtil.OnDownloadListener() {
                            @Override
                            public void onDownloadSuccess(File downfile, File file) {
                                hand();
                                stopSelf();
                            }
                            @Override
                            public void onDownloading(int progress, File file) {
                                LogUtil.i("update progress---"+progress);
                                broadCast.putExtra("download", progress);
                                sendBroadcast(broadCast);
                            }
                            @Override
                            public void onDownloadFailed(String error) {
                            }
                        });
                    } catch (Exception e) {
                    }
                }
            }).start();
        } else {
            Toast.makeText(getApplicationContext(), "网络无连接,请稍后下载!",
                    Toast.LENGTH_SHORT).show();
        }
    }
代码语言:javascript
复制
 /**
     * 打开附件的方法
     * @param f
     * @param context
     */
    public void openFile(File f, Context context) {
        Log.i(LOGTAG, "正在打开附件打--------" + f.getName()+"。附件大小为"+f.length());
        try {
            String end = f.getName().substring(f.getName().lastIndexOf(".")
                    + 1, f.getName().length()).toLowerCase();
            if(end.equals("amr")){
                AudioRecoderUtils.getInstance().playerStart(f.getAbsolutePath());
            }else {
                Intent intent = new Intent();
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                intent.setAction(android.content.Intent.ACTION_VIEW);
                intent.addCategory("android.intent.category.DEFAULT");
      /* 调用getMIMEType()来取得MimeType */
                String type = getMIMEType(f);
      /* 设置intent的file与MimeType */
                if(Build.VERSION.SDK_INT>=24){
                    Uri contenturi=FileProvider.getUriForFile(context, "com.mintu.dcdb.fileprovider",f);
                    intent.setDataAndType(contenturi,type);
                    intent.putExtra(MediaStore.EXTRA_OUTPUT, contenturi);
                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                }else{
                    intent.setDataAndType(Uri.fromFile(f), type);
                }
                context.startActivity(intent);
            }
        } catch (Exception e) {
//            Toast.makeText(context,"打开附件---"+f.getName()+",发生了错误",Toast.LENGTH_SHORT).show();
            Log.e(LOGTAG, "打开附件" + f.getName() + "报错了,错误是-----" + e.getMessage());
        }
    }

项目中全量更新源码:

代码语言:javascript
复制
package com.mintu.dcdb.util.updateAppUtil;

import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.text.Html;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.google.gson.Gson;
import com.mintu.dcdb.R;
import com.mintu.dcdb.config.Constant;
import com.mintu.dcdb.config.RequestUrl;
import com.mintu.dcdb.main.bean.UpdateBean;
import com.mintu.dcdb.main.view.UpdateDialog;
import com.mintu.dcdb.util.LogUtil;
import com.wusy.wusylibrary.base.BaseActivity;
import com.wusy.wusylibrary.util.CommonUtil;
import com.wusy.wusylibrary.util.OkHttpUtil;
import com.wusy.wusylibrary.util.SharedPreferencesUtil;

import java.io.IOException;
import java.util.ArrayList;

import okhttp3.Call;

/**
 * Created by XIAO RONG on 2018/7/19.
 */

public class UpdateAppUtil {
    private SharedPreferencesUtil sharedPreferencesUtil;
    private BaseActivity activity;
    private  ProgressDialog m_pDialog;
    private boolean isAutoUpdate=false;

    public UpdateAppUtil(BaseActivity activity,boolean isAutoUpdate){
        sharedPreferencesUtil=SharedPreferencesUtil.getInstance(activity);
        this.activity=activity;
        this.isAutoUpdate=isAutoUpdate;
    }

    public void updateApp(){
        String url = RequestUrl.getInstance().getUpdateUrl((String) SharedPreferencesUtil.getInstance(activity).getData(Constant.VERSION_CODE, ""));
        OkHttpUtil.getInstance().asynGet(url, new OkHttpUtil.ResultCallBack() {
            @Override
            public void successListener(Call call, String responseStr) {
                LogUtil.i("update result str--"+responseStr);
                Gson gson = new Gson();
                UpdateBean bean = gson.fromJson(responseStr, UpdateBean.class);
                sharedPreferencesUtil.saveData(Constant.VERSION_CODE,bean.getVersion());
                sharedPreferencesUtil.saveData(Constant.VERSION_URL,bean.getUrl());
                sharedPreferencesUtil.saveData(Constant.VERSION_CONTENT,bean.getContent());
                sharedPreferencesUtil.saveData(Constant.VERSION_PATCH_FILE_PATH,bean.getPatchFilePath());
                sharedPreferencesUtil.saveData(Constant.VERSION_IS_PATCH_FILE_PATH,bean.getIsPatchFilePath());
                activity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        checkVersion();
                    }
                });
            }

            @Override
            public void failListener(Call call, IOException e) {

            }
        });
    }
    /***
     * 检查是否更新版本
     */

    private void checkVersion() {

        if (Integer.parseInt((String) sharedPreferencesUtil.getData(Constant.VERSION_CODE_LOCAL,"")) < Integer
                .parseInt(CommonUtil.getInstance().isNull(sharedPreferencesUtil.getData(Constant.VERSION_CODE,"")) ? "0"
                        : (String) sharedPreferencesUtil.getData(Constant.VERSION_CODE,""))) {
            showDialog(new DownLoadBroadCastReceiver());
        }else{
            if(!isAutoUpdate) Toast.makeText(activity, "未检查到新版本", Toast.LENGTH_SHORT).show();
        }
    }
    private void showDialog(final BroadcastReceiver receiver) {
        final Dialog alert = new UpdateDialog(activity, R.style.MyDialogStyle);
        alert.setContentView(R.layout.upgrade_dialog);
        TextView tvView = (TextView) alert.findViewById(R.id.upgradeText);
        if (!CommonUtil.getInstance().isNull(sharedPreferencesUtil.getData(Constant.VERSION_CONTENT, ""))) {
            tvView.setText(Html.fromHtml((String) sharedPreferencesUtil.getData(Constant.VERSION_CONTENT, "")));
        }

        tvView.setWidth(activity.getWindowManager().getDefaultDisplay().getWidth() * 3 / 4);
        Button sureBtn = (Button) alert.findViewById(R.id.btn_sure);
        Button cancleBtn = (Button) alert.findViewById(R.id.btn_cancle);

        sureBtn.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {


                ArrayList<String> actionList = new ArrayList<>();
                actionList.add(Constant.DOWNLOAD_ACTION);
                activity.addBroadcastAction(actionList, receiver);
                Intent updateIntent = new Intent(activity,
                        UpdateService.class);
                updateIntent.putExtra("app_name", activity.getResources()
                        .getString(R.string.app));

                activity.startService(updateIntent);
                alert.dismiss();
            }
        });
        cancleBtn.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                alert.dismiss();
            }
        });
        alert.show();
    }
    class DownLoadBroadCastReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            switch (intent.getAction()) {
                case Constant.DOWNLOAD_ACTION:
                    int progress = intent.getIntExtra("download", 0);
                    showProgress(progress);
                    break;

                default:
                    break;
            }

        }
    }
    private void showProgress(Integer progress) {
        if (m_pDialog == null) {
            createProgressDialog("正在更新请稍后...");
        }
        m_pDialog.setProgress(progress);
        if (progress == 100) {
            m_pDialog.dismiss();
        }
    }
    private void createProgressDialog(String title) {

        // 创建ProgressDialog对象
        m_pDialog = new ProgressDialog(activity);

        // 设置进度条风格,风格为长形
        m_pDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);

        // 设置ProgressDialog 标题
        m_pDialog.setTitle(title);
        // 设置ProgressDialog 进度条进度
        m_pDialog.setProgress(100);

        // 设置ProgressDialog 的进度条是否不明确
        m_pDialog.setIndeterminate(false);

        // 设置ProgressDialog 是否可以按退回按键取消
        m_pDialog.setCancelable(true);
        // 设置点击进度对话框外的区域对话框不消失
        m_pDialog.setCanceledOnTouchOutside(false);
        // 让ProgressDialog显示
        m_pDialog.show();
    }
}
代码语言:javascript
复制
package com.mintu.dcdb.util.updateAppUtil;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.ProgressDialog;
import android.app.Service;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;

import com.mintu.dcdb.config.Constant;
import com.mintu.dcdb.util.LogUtil;
import com.mintu.dcdb.util.SystemUtils;
import com.wusy.wusylibrary.util.CommonUtil;
import com.wusy.wusylibrary.util.OkHttpUtil;
import com.wusy.wusylibrary.util.SharedPreferencesUtil;

import java.io.File;

/**
 *
 * Filename: UpdateService.java Description: 今天修改了当增量包合成失败的时候,重新下载整个最新的apk
 * Company: minto
 *
 * @author: chjr
 * @version: 2.8.0 Create at: 2016年5月20日 下午3:25:52
 *
 */
public class UpdateService extends Service {
    private final int TIMEOUT = 10 * 1000;// 超时
    private final int DOWN_OK = 1;
    private final int DOWN_ERROR = 0;
    private String app_name;
    private String file_name;

    private NotificationManager notificationManager;
    private Notification notification;

    private Intent updateIntent;
    private PendingIntent pendingIntent;

    private int notification_id = 0;
    ProgressDialog m_pDialog;
    private File updateDir = new File(Constant.FILEDIR);
    File updateFile;
    SharedPreferencesUtil vsPreference;
    String packageName = "com.minto.workhi";
    String patchUrl = Constant.FILEDIR;
    String newApkUrl = Constant.FILEDIR;
    private String downUrl = "";
    private int flag = 2;
    private Intent broadCast;
    @Override
    public IBinder onBind(Intent arg0) {
        stopSelf();
        return null;
    }
    @Override
    public void onCreate() {
        super.onCreate();
        vsPreference = SharedPreferencesUtil.getInstance(getApplicationContext());
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        if (CommonUtil.getInstance().isNull(intent)) {
            stopSelf();
            Log.d("UpService", intent + "--------------------");
        } else {

            app_name = intent.getStringExtra("app_name");
            file_name = app_name + ".apk";


            patchUrl = patchUrl + app_name + ".patch";
            // 创建文件
            CommonUtil.getInstance().createFile(app_name + ".patch");
            CommonUtil.getInstance().createFile(file_name);
            updateFile = new File(updateDir + "/" + app_name + ".patch");
            if(flag==1)flag=2;
            broadCast = new Intent();
            broadCast.setAction(Constant.DOWNLOAD_ACTION);
            broadCast.putExtra("download", 0);
            sendBroadcast(broadCast);
            downFile();
        }
        return super.onStartCommand(intent, flags, startId);
    }

    /***
     * 开线程下载
     */
    public void createThread(final String downUrl) {
        final Message message = new Message();
        if (SystemUtils.isNetworkAvailable(getApplicationContext())) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        OkHttpUtil.getInstance().download(downUrl, newApkUrl, file_name, new OkHttpUtil.OnDownloadListener() {
                            @Override
                            public void onDownloadSuccess(File downfile, File file) {
                                hand();
                                stopSelf();
                            }
                            @Override
                            public void onDownloading(int progress, File file) {
                                LogUtil.i("update progress---"+progress);
                                broadCast.putExtra("download", progress);
                                sendBroadcast(broadCast);
                            }
                            @Override
                            public void onDownloadFailed(String error) {
                            }
                        });
                    } catch (Exception e) {
                    }
                }
            }).start();
        } else {
            Toast.makeText(getApplicationContext(), "网络无连接,请稍后下载!",
                    Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 根据类型下载不同的文件
     *
     * @exception
     * @since 1.0.0
     */
    protected void downFile() {
        // 下载增量包路径
        if (1 == flag) {
            downUrl = (String) vsPreference.getData(Constant.VERSION_PATCH_FILE_PATH,"");
        } else if (2 == flag) {
            downUrl = (String) vsPreference.getData(Constant.VERSION_URL,"");
        }
        createThread(downUrl);
    }

    /**
     * 根据不同的包安装
     *
     * @exception
     * @since 1.0.0
     */
    protected void hand() {
        // 增量合成方法
        if (1 == flag) {
//          ApkUpdate update = new ApkUpdate(getApplicationContext(),
//                  packageName, patchUrl, newApkUrl);
//          // 检查低版本的apk 是否存在
//          if (update.isOldApkExist()) {
//              // 判断是否成功合成新的apk
//              if (update.newApkGet()) {
//                  update.installApk();
//                  delData();
//              } else {
//                  // Toast.makeText(getApplicationContext(),
//                  // "下载失败!:" + newApkUrl + "增量包地址:" + patchUrl,
//                  // Toast.LENGTH_SHORT).show();
//                  flag = 2;
//                  downFile();
//              }
//          }
        }
        // 整包安装方法
        else if (2 == flag) {
            File apkFile = new File(newApkUrl, file_name);
            OkHttpUtil.getInstance().openFile(apkFile,this);
        }
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.08.09 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 实现思路:
  • 注意:
  • 核心代码:
  • 项目中全量更新源码:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档