APP 版本升级功能设计

1,962 阅读4分钟

一、背景

随着业务的不断发展而叠加的功能、产品发展到一定程度需要大改版提升用户体验、程序出现BUG、政策原因需要紧急关闭某些功能等等。这些场景都会成为APP更新版本的理由

二、更新类型

1、静默更新
  1. 功能解释:静默更新是由手机悄悄的更新,一般用户在应用市场勾选了Wifi状态下,闲时自动更新功能,手机系统会按规则帮助用户自动更新APP,此功能和用户手动点击更新一样,只是由系统帮用户做了。
  2. 适用场景: 在APP发布新版后,并没有什么紧急或较紧急的诉求希望用户尽快更新APP的,都可以选择静默更新。
2、强更新
  1. 功能解释:强更新是指用户必须更新,否则不允许使用APP,非常的强制和粗暴。用户只能接受,否则无法使用。
  2. 适用场景:一般是系统重构,发生了数据迁移;或者大功能上线,替代了老功能;或者是严重BUG。总之,是牺牲用户体验,也要非升不可的场景才会用上。
3、弱更新

功能解释:弱更新是指,在用户进入到APP后,弹窗提示用户升级版本,用户可以选择升,也可以不升正常用。也就是说,升不升用户说了算。是一种比较友好的用户体验,选择权交给了用户。

适用场景:不希望牺牲用户体验,但是又希望用户快点升级到新版本体验新的功能或者更佳的视觉、交互体验等场景

三、升级样式

业界常用的更新方式,着重对于新功能和弱更新的提示

四、ios 端升级提示

4-1、ios 支付方案升级举例

针对 ios 支付问题,功能性的强制更新可以在老用户触发支付时进行强制提示

目前正常支付功能的版本在 13 这个版本, 可以判断用户版本为空或者低于13时,点击支付进行用户更新才可以正常使用发放权限

以下是流程示意图

image.png

image.png

4-2、ios 测试验证流程

在邮箱的测试邮件中选择点击 TestFight 进行安装, 安装时候不要安装最新版本,在APP信息中有版本与 Build 群组,点击选择历史版本安装历史版本即可

image.png

4-3、代码实现

1、Ios 端

Ios 端获取当前版本和版本号注入h5中,前期为了简单起见,只注入了构建版本号

// 获取版本号
NSString *appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
NSString *appBuild = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
NSString *jsString = [NSString stringWithFormat:@"window.__iosApp__ = true; window.__iosAccount__ = 'v2'; window.iosBuildCode = %@",appBuild];
2、h5 端

useAppVersionUpdate.tsx 中

const curVersion = window.iosBuildCode
// 判断当前功能是否具有跳转app的能力,有增加更新按钮用户点击跳转app store下载最新版本, 没有则只提示
const showUpdateBtn = curVersion >= featureVersion["sharedApplication"]?.code;

//  跳转app store 更新app
iosBridge.pubSub.publish(messageKey.sendToNative, messageKey.sharedApplication, {
    url: "",
    appStoreUrl: "itms-apps://itunes.apple.com/app/id6670308912,
});

一些可用的功能及版本管理

五、google play app 版本升级

5-1、系统更新提示

在资源管理器中是可以在上传了最新版本后, 看到上一个版本的安装人数,并且可以点击提示用户更新, 但是经过测试应该是无法自动提示更新的, 需要代码中增加检测升级的代码 , 代码如下

private lateinit var updateActivityResultLauncher: ActivityResultLauncher<IntentSenderRequest>
private lateinit var m_appUpdateManager: AppUpdateManager

//...

override fun onCreate(savedInstanceState: Bundle?) {
    m_appUpdateManager = AppUpdateManagerFactory.create(this)
    // 注册用于处理更新结果的 ActivityResultLauncher
    updateActivityResultLauncher = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result: ActivityResult ->
    // handle callback
        if (result.resultCode != RESULT_OK) {
            Log.d("更新成功", "更新成功" + result.resultCode)
        }
    }
   // 检测谷歌版本更新
   checkGooglePlayUpdate()
}

/**
* google play 应用更新
*/
fun checkGooglePlayUpdate(){
    val appUpdateInfoTask: Task<AppUpdateInfo> = m_appUpdateManager.getAppUpdateInfo()
    appUpdateInfoTask.addOnSuccessListener { appUpdateInfo: AppUpdateInfo ->
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE // This example applies an immediate update. To apply a flexible update
            && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)
        ) {
            try {
                m_appUpdateManager.startUpdateFlowForResult(
                    appUpdateInfo,
                    updateActivityResultLauncher,
                    AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE).build())
            } catch (e: IntentSender.SendIntentException) {
                e.printStackTrace()
            }
        }
    }
}

此处更新的类型为 AppUpdateType.IMMEDIATE 为立即更新, 也可以选择 AppUpdateType.FLEXIBLE 灵活模式

5-2、h5 内代码功能提示版本升级弹窗

自定义功能的版本升级同上 ios 的逻辑

不同的是,android 上版本信息不是通过js注入的,通过在h5内监听初始化版本信息进行监听

 /**
* 获取当前版本
*/
private fun getAppInfoToJson(): String {
    var pm: PackageManager? = packageManager
var packageName: String = getPackageName()
    var packageInfo: PackageInfo = pm!!.getPackageInfo(packageName, 0)
    var versionCode: Int = packageInfo.versionCode
    var versionName: String = packageInfo.versionName
    val gson = Gson();
    val info = mapOf(
        "versionCode" to versionCode,
        "versionName" to versionName,
        "packageName" to packageName
    )
    return base64Encode(gson.toJson(info))
}

@JavascriptInterface
fun initAppInfo(): String {
    return getAppInfoToJson();
}

H5 端获取安卓版本信息代码

useAppInfo.ts 中

export const useAppInfo = () => {
    function setAndroidInfo() {
    const info = window.Android?.initAppInfo?.();
    if (info) {
      const stringData = base64Decode(info);
      const parseData: AndroidInfo = JSON.parse(stringData);
      window.Android.versionCode = parseData.versionCode;
      window.Android.versionName = parseData.versionName;
      window.Android.packageName = parseData.packageName;
      if (
        Number(window.Android.versionCode) >= androidFeatureVersion.andriod_screen_top_full_code22.code &&
        document.querySelector("body")
      ) {
        document.querySelector("body")?.classList.add("android_webview_22_screen_top");
      }
    }
  }
  
  // 调用安卓上的获取版本信息的方法
  useEffect(() => {
     setAndroidInfo();
  }, []);
}

5-3、版本升级测试

安卓的版本测试比ios版本测试要简单一些, 可以在打包时直接打包低版本的 sdk 进行测试