Skip to main content
Version: v3

唤起更新开发指南

TapTap 开发者服务为游戏和玩家提供唤起 TapTap 客户端更新游戏的功能。

当游戏发布了新版本,且需要玩家进行更新才能体验新版本时,在游戏内绘制一个界面告知玩家并提供「更新」按钮。

玩家点击按钮调用 updateGameAndFailToWebInTapTap 接口,此时跳转到 TapTap 客户端内的游戏详情页,玩家在 TapTap 内完成更新。

info

唤起更新只提供「唤起 TapTap 客户端,跳转至游戏详情页」这一简单功能。

TapTap 上游戏的版本号来自开发者在构建新版本时上传的 APK,唤起更新功能并不提供「检查 TapTap 商店是否有新版本」接口,游戏需自行实现判断版本的功能。

SDK 获取

SDK 可以通过 Unity Package Manager 导入或手动导入,二者任选其一。

如果选择 UPM 导入,可以在项目的 Packages/manifest.json 文件中添加:

"dependencies":{
"com.taptap.tds.common":"https://github.com/TapTap/TapCommon-Unity.git#3.29.4",
"com.leancloud.storage": "https://github.com/leancloud/csharp-sdk-upm.git#storage-2.3.0",
}

如果选择手动导入:

  • 下载页 找到 TapSDK Unity 下载地址,下载 TapSDK-UnityPackage.zip 然后解压,导入其中的 TapTap_Common 模块。
  • 下载 LeanCloud-SDK-Storage-Unity.zip,解压后为 Plugins 文件夹,拖拽至 Unity 即可。

唤起 TapTap 检查更新

tip

自 TapSDK 3.3.0 版本开始,针对更新功能做了逻辑优化,唤起 TapTap 客户端更新游戏失败时可以跳转到自定义网页。TapSDK 3.3.0 版本对之前的版本向下兼容。 该版本一般情况下不需要在使用以下 API 前特别检查是否安装 TapTap 客户端,自 TapSDK 3.3.0 版本开始推荐使用新接口。

在 TapTap 客户端更新游戏,失败时通过浏览器打开 TapTap 网站对应的游戏页面:

bool isSuccess = await TapCommon.UpdateGameAndFailToWebInTapGlobal(string appId);

唤起 TapTap 客户端更新游戏失败,跳转到自定义网页:

bool isSuccess = await TapCommon.UpdateGameAndFailToWebInTapGlobal(string appId, string webUrl);

打开游戏评论区

TapCommon.OpenReviewInTapGlobal(appId, openSuccess =>
{
if (openSuccess) {
Debug.Log("打开游戏评论区成功");
}
});

appid:游戏在 TapTap 商店的唯一身份标识。 例如:https://www.taptap.io/app/187168,其中 187168appid

常见问题

未接入 TapSDK,如何唤起 TapTap 客户端更新游戏

受限于苹果政策,iOS 平台的 TapTap 客户端不提供游戏更新功能,以下方案仅限于 Android 平台使用。

未接入 TapSDK、使用旧版 TapSDK 难以升级的游戏,可以通过以下方案进行手动唤起 TapTap 客户端更新游戏:

根据玩家设备是否安装 TapTap 客户端来对应打开 URL:

  • 如果玩家设备安装 TapTap 客户端则直接唤起 TapTap 客户端到游戏详情页进行更新;
  • 如果玩家设备没有安装 TapTap 客户端,则以 Web 形式打开游戏详情页,根据页面底部提示引导玩家下载 TapTap 客户端,安装成功后打开 TapTap 客户端,玩家根据提示选择在 TapTap 客户端里打开游戏详情页进行更新。

未安装 TapTap 客户端对应的 URL:

  • https://l.taptap.io/GNYwFaZr?subc1=AppID

已安装 TapTap 客户端对应的 URL:

  • tapglobal://taptap.tw/app?app_id=游戏商店id&source=outer|update

注意替换其中的 AppIDAppID 是游戏在 TapTap 商店的唯一身份标识,例如:https://www.taptap.io/app/187168,其中 187168 是 AppID。

注意,除了打开 URL 外,还需要检测设备是否已经安装 TapTap 客户端,以及处理唤起失败的逻辑,这些代码都需要自行编写。

下面提供 TapSDK 唤起更新的代码供参考。

参考代码
package com.tds.common.utils;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import java.util.Locale;

public class TapGameUtil {

private static final String TAG = TapGameUtil.class.getName();

public static final String PACKAGE_NAME_TAPTAP_GLOBAL = "com.taptap.global";

public static final String CLIENT_URI_TAPTAP_GLOBAL = "tapglobal://taptap.tw";

public static final String DEFAULT_CLIENT_DOWNLOAD_URL_TAPTAP_GLOBAL = "https://l.taptap.io/GNYwFaZr";

// 这里更新的时候不检查 Tap 客户端,一是因为特定 schema 没被应用注册的话大概率是直接返回 error 的,在这里被 try catch 后返回 false 可以近似等于客户端不存在
// 二是因为 Android 11 开始检查客户端需要游戏做特殊配置,这个配置无法在 SDK 内做好,因为和编译工具版本强绑定,无法做前后版本兼容。

public static boolean updateGameAndFailToWebInTapGlobal(Activity activity, String appId) {
return updateGameInTapGlobal(activity, appId) || openWebDownloadUrlOfTapGlobal(activity, appId);
}

public static boolean updateGameAndFailToWebInTapGlobal(Activity activity, String appId, String webUrl) {
if (TextUtils.isEmpty(webUrl)) {
return updateGameAndFailToWebInTapGlobal(activity, appId);
}
return updateGameInTapGlobal(activity, appId) || openWebDownloadUrl(activity, webUrl);
}

public static boolean isTapGlobalInstalled(Context context) {
return isTapClientInstalled(context, PACKAGE_NAME_TAPTAP_GLOBAL);
}

public static boolean isTapClientInstalled(Context context, String clientPackageName) {
if (context != null && !TextUtils.isEmpty(clientPackageName)) {
boolean TapTapInstalled = false;
try {
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(clientPackageName, 0);
if (null != packageInfo) {
TapTapInstalled = true;
}
} catch (Exception e) {
Log.e(TAG, clientPackageName + " isInstalled=false");
}
return TapTapInstalled;
}
return false;
}

public static boolean updateGameInTapGlobal(Activity activity, String appId) {
return updateGameInTapClient(activity, appId, CLIENT_URI_TAPTAP_GLOBAL);
}

public static boolean updateGameInTapClient(Activity activity, String appId, String clientUri) {
if (activity != null && !TextUtils.isEmpty(appId) && !TextUtils.isEmpty(clientUri)) {
try {
Uri uri = Uri.parse(String.format(Locale.US,
"%s/app?app_id=%s&source=outer|update", clientUri, appId));
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(intent);
} catch (Exception e) {
Log.e(TAG, clientUri + "updateGameInTapTap failed");
return false;
}
return true;
}
Log.e(TAG, clientUri + "updateGameInTapTap failed");
return false;
}

public static boolean openReviewInTapGlobal(Activity activity, String appId) {
return openReviewInTapClient(activity, appId, CLIENT_URI_TAPTAP_GLOBAL);
}

public static boolean openReviewInTapClient(Activity activity, String appId, String clientUri) {
if (activity != null && !TextUtils.isEmpty(appId) && !TextUtils.isEmpty(clientUri)) {
try {
Uri uri = Uri.parse(String.format(Locale.US,
"%s/app?tab_name=review&app_id=%s", clientUri, appId));
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(intent);
} catch (Exception e) {
Log.e(TAG, clientUri + "openTapTapReview failed");
return false;
}
return true;
}
Log.e(TAG, clientUri + "openTapTapReview failed");
return false;
}

public static boolean openWebDownloadUrlOfTapGlobal(Activity activity, String appId) {
return openWebDownloadUrl(activity, String.format(Locale.US, DEFAULT_CLIENT_DOWNLOAD_URL_TAPTAP_GLOBAL + "?subc1=%s", appId));
}

public static boolean openWebDownloadUrl(Activity activity, String url) {
if (activity != null && !TextUtils.isEmpty(url)) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setData(Uri.parse(url));
activity.startActivity(intent);
} catch (Exception e) {
Log.e(TAG, "openWebUrl fail");
return false;
}
return true;
}
return false;
}

}