放出一款APP更新的SDK

1,410 阅读5分钟

背景

在开发过程中做为组件分出来的app更新组件,我觉得可以做为一个简单的更新SDK用于别的项目中,就调整了一些api开放SDK出来给有需要的同学使用吧,当然适用性方面肯定不如项目定制那么强的,只是快速接入更新功能的话挺好的。

功能很简单,就是获取更新信息,下载,安装。

github仓库地址:github.com/ywp0919/Apk…

简单效果图

由于下载太快了,就不上其他的图片了。

使用前配置

  1. project里面需要依赖
	allprojects {
		repositories {
			...
			maven { url 'https://jitpack.io' }
		}
	}
  1. app 里面需要依赖
	dependencies {
	        implementation 'com.github.ywp0919:ApkUpdate:1.4.0'
	}
  1. manifest里面需要添加provider,如果已有则不需要再重复,刚在xml看看是否需要添加选项
	        <provider
               android:name="androidx.core.content.FileProvider"
               android:authorities="{这里填自己app的包名}.fileprovider"
               android:exported="false"
               android:grantUriPermissions="true">
               <meta-data
                   android:name="android.support.FILE_PROVIDER_PATHS"
                   android:resource="@xml/filepath" />
           </provider>
  1. @xml/filepath配置
<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <external-path name="download" path="."/>
</paths>

api使用方法

可以参考demo的MainActivity里面,主要有以下一些api,看看示例很好看明白。

首先说明一下内部使用的接口格式,如果外部不单独配置的话,就需要后台接口按这个格式返回数据,如下:

    {
      "updateLog": "\r\n1、优化接口。\r\n2、优化更新提示界面。",
      "updateTitle":"更新标题",
      "appName": "UpdateDemo",
      "packageName": "com.wepon.apkupdate",
      "versionCode": 2,
      "versionName": "1.2",
      "force": false,
      "apkUrl": "https://wepon.oss-cn-hangzhou.aliyuncs.com/apkupdate_lib/apkupdate_version_2.apk",
      "apkHash": "",
      "apkSize": ""
    }
  1. 最简单的方式,填入更新接口的url就行了,不过接口的json格式要和sdk内部默许的对上。
   public void testNetApiData(View view) {
       ApkUpdate.newBuilder()
               .setUpdateInfoUrl("https://wepon.oss-cn-hangzhou.aliyuncs.com/apkupdate_lib/updateInfo") // 获取升级信息接口,demo这步是乱填的。
               .update(this); //需要传入activity是因为有弹框提示的dialog。
   }
  1. 用户自定义UI,通过接口回调状态去自定义UI.
ApkUpdate.newBuilder()
      .setUpdateInfoUrl("https://wepon.oss-cn-hangzhou.aliyuncs.com/apkupdate_lib/updateInfo") // 获取升级信息接口,demo这步是乱填的。
      // 设置了是否有更新的监听处理,如果设置了这个,内部就不会进行弹窗以及之后的流程了。
      // 用户可以根据以下回调自定义 升级显示的UI. 如果使用内置的则不需要设置此方法 。
      .setApkUpdateManagerListener(new ApkUpdateManagerListener() {
          @Override
          public void onNoUpdateAvailable() {
              // 没有更新
              tvShow.setText("自定义显示:没有更新");
          }

          @Override
          public void onUpdateAvailable(final ApkUpdateBean apkUpdateBean) {
              // 有新的升级
              // 在这里用户可以自行下载,也可以调用sdk进行下载,如:
              // 注意,这里的url只能使用onUpdateAvailable回调的这个对象里面的url,不支持其他的。

              // show update dialog
              new AlertDialog.Builder(MainActivity.this)
                      .setTitle(apkUpdateBean.getUpdateTitle())
                      .setMessage(apkUpdateBean.getUpdateLog())
                      .setCancelable(true)
                      .setPositiveButton("立即更新", new DialogInterface.OnClickListener() {
                          @Override
                          public void onClick(DialogInterface dialog, int which) {
                              // 同时可以显示下载的进度ui
                              tvShow.setText("自定义显示:开始更新");

                              // 去下载更新。
                              ApkUpdate.downloadApk(apkUpdateBean.getApkDownloadUrl());
                          }
                      })
                      .create()
                      .show();

              tvShow.setText("自定义显示:有更新");
          }
      })
      // 用户可以根据以下回调自定义下载的UI. 如果使用内置的则不需要设置此方法.
      // 如果不接收回调,内部则会在下载完成后自动调用安装逻辑
      // 主线程回调
      .setApkDownloadListener(new ApkDownloadListener() {
          @Override
          public void downloadFailed(Throwable throwable) {
              // 下载失败
              // 可以取消进度ui
              Log.d("Wepon", "downloadFailed:" + throwable.getLocalizedMessage());
              tvShow.setText("自定义显示进度 : 下载失败 ");
          }

          @Override
          public void downloadSuc(Uri uri) {
              // 下载成功
              // 可以取消进度ui
              // 可以使用sdk的方法进行安装
              ApkUpdate.installApk(uri);

              Log.d("Wepon", "downloadSuc uri:" + uri.getPath());

              tvShow.setText("自定义显示进度 : 下载完成 ");
          }

          @Override
          public void onProgressUpdate(int progress) {
              // 进度回调,值为0-100.
              Log.d("Wepon", "progress:" + progress);
              // 可以刷新进度ui
              tvShow.setText("自定义显示进度 : " + progress + "%");

          }
      })
      .update(this);

3.自定义配置更新接口的json字段,以及其他api的展示。

    private ApkUpdate.Builder getApkUpdateBuilder() {
        ApkUpdateApiFieldBean bean = new ApkUpdateApiFieldBean();
        bean.setApkDownloadUrlFieldName("apkDownloadUrl"); // apk下载地址的字段
        bean.setIsForceUpdateFieldName("isForceUpdate");// 是否强制升级的字段
//        bean.setIsNeedUpdateFieldName("isNeedUpdate"); // 此次是否需要更新
        bean.setVersionCodeFieldName("versionCode");// 新版本VersionCode对应的字段
        bean.setUpdateLogFieldName("updateLog"); // 升级窗口需要显示的内容
        bean.setUpdateTitleFieldName("updateTitle");// 升级显示需要显示的标题

        return ApkUpdate.newBuilder()
                .setForceUpdate(false) // 本地设置是否强制更新 (升级接口也可以配置字段来实现是否强制升级,两者有一个强制即为强制)
                .setGetHttp(true) // get请求,否则post请求。
                .setUpdateInfoUrl("https://xxx.yyyy") // 获取升级信息接口,demo本地数据示例的这一步是乱填的。
                .setUpdateInfoParams(new HashMap<String, Object>()) // 获取升级信息接口需要的参数,不需要可以不传。
                .setApiFieldBean(bean) // 设置一些字段名称
                // ApkUpdate里面的异常信息回调,不捕获的话就不加这个就行。
                .setErrorInfoCallback(new ApkUpdate.ErrorInfoCallback() {
                    @Override
                    public void onError(Throwable throwable) {
                        Toast.makeText(MainActivity.this, throwable.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
                    }
                });
    }

    /**
     * 代理网络请求方式
     */
    public void testLocalData1(View view) {
        // demo 这里实际使用时需要用app的网络请求框架来请求真实数据,demo用的假数据,没做网络请求。
        getApkUpdateBuilder()
                // 这里可以设置成app调用方的网络请求框架。
                .setUpdateHttpServer(new IApkUpdateHttpServer() {
                    @Override
                    public void asyncGet(@NonNull String url, @NonNull Map<String, Object> params, @NonNull Callback callBack) {
                        // 这里回传了一份假json数据,实际应用时需要做网络请求获取到数据。
                        // 通过调用者的网络框架获取到数据后回调  callBack.onSuccess();
                        success(callBack);
                    }

                    @Override
                    public void asyncPost(@NonNull String url, @NonNull Map<String, Object> params, @NonNull Callback callBack) {
                        success(callBack);
                    }
                })
                .update(this);// 需要传入一个activity来显示dialog信息。
    }

    /**
     * 传入调用者已经生成的json string,内部可以解析这个json,走后面的流程。
     */
    public void testLocalData2(View view) {
        // 有些时候如果外部拿到了升级接口的json数据,也可以转换后传入直接调用。
        getApkUpdateBuilder()
                .updateByJsonStr(getTestUpdateJsonString(), this);// 需要传入一个activity来显示dialog信息。
    }

    /**
     * 下面的数据都是测试时用的假数据,测试apkDownloadUrl下载地址也需要自己弄一个...
     */
    private void success(IApkUpdateHttpServer.Callback callBack) {
        callBack.onSuccess(getTestUpdateJsonString());
    }

    private String getTestUpdateJsonString() {
        return "{\n" +
                "\"isNeedUpdate\": true,\n" +
                "\"isForceUpdate\": false,\n" +
                "\"versionCode\": 2,\n" +
                "\"versionName\": \"1.2\",\n" +
                "\"updateTitle\": \"重大更新\",\n" +
                "\"updateLog\": \"\\r\\n1、优化接口。\\r\\n2、优化更新提示界面。\",\n" +
                "\"apkDownloadUrl\": \"https://wepon.oss-cn-hangzhou.aliyuncs.com/apkupdate_lib/apkupdate_version_2.apk\"\n" +
                "}";
    }

END

有需要的同学可以用一用哦,如果对库有什么好的建议的话后续可以更新进来。