本篇文章是官网中文版。有外网的小伙伴可以直接访问官网地址和代码示例
https://developer.android.com/google/play/billing/billing_integrate?hl=zh-cn
https://github.com/googlesamples/android-play-billing
In-app Billing API
您的应用会通过相应 API (由设备上安装的 Google Play 应用提供)来访问应用内购买结算服务。 然后,Google Play 应用会在您的应用和 Google Play 服务器之间传送购买结算请求和响应。 实际上,您的应用从不直接与 Google Play 服务器通信。 而是通过进程间通信 (IPC) 向 Google Play 应用发送购买结算请求并接收 Google Play 应用发来的响应。此外,您的应用也不管理其与 Google Play 服务器之间的任何网络连接。
应用内购买结算只能在您通过 Google Play 发布的应用中实现。 要完成应用内购买请求,Google Play 应用必须能够通过网络访问 Google Play 服务器。
应用内购买结算版本 3 是最新版本,依然具有非常广泛的兼容性,可用于各种 Android 设备。 运行 Android 2.2(API 级别 8)或更高版本且安装了最新版本的 Google Play 应用的设备(绝大多数有效设备)都支持使用应用内购买结算版本 3。
版本 3 的功能
应用内购买结算版本 3 提供以下功能:
- 您的应用通过简化的 API 发送请求,让用户可以轻松地向 Google Play 请求商品详情并订购应用内商品。 API 可以根据用户对商品的所有权快速恢复商品。
- API 会在购买完成时将订单信息同步传送至设备。
- 所有购买都是托管的(也就是说,Google Play 负责跟踪用户对应用内商品的所有权)。 用户无论何时都只能拥有同一应用内商品的一个副本而不能拥有多个副本。
- 您可以消耗所购商品。消耗后,此商品将切换回未被拥有状态,且可被用户从 Google Play 中再次购买。
- API 支持订阅。
如需了解有关其他版本的应用内购买结算的详情,请参阅版本说明。
应用内商品
应用内商品是您在应用内向用户出售的数字商品。 包括游戏内货币、旨在改善用户体验的应用功能升级以及应用中的新增内容。
应用内购买结算只能用于销售数字内容,而不能用于销售实体商品、个人服务或任何需要进行实物交付的商品/服务。 与明码标价的应用不同,在用户购买应用内商品后,系统不会提供退款窗口。
Google Play 不提供任何形式的内容交付。您需要自行负责在应用中出售的数字内容的交付。 应用内商品始终仅与一个应用明确关联。 也就是说,在一个应用中不能购买为另一个应用发布的应用内商品,即使这两个应用来自相同的开发者也是如此。
商品类型
应用内购买结算支持多种商品类型,因此您可灵活选择如何通过您的应用获利。 无论是哪种商品,您均能通过 Google Play Developer Console 进行定义。
您可以为应用内购买结算应用指定以下两类商品:托管的应用内商品和订阅。 Google Play 会针对每位用户处理和跟踪您应用中的应用内商品和订阅的所有权。详细了解应用内购买结算版本 3 支持的商品类型。
Google Play Developer Console
在 Developer Console 上,您不仅能发布应用内购买结算应用,还能管理在您应用中可以购买的各种应用内商品。
对于与您的应用相关联的数字商品(包括一次性商品和定期订阅),您可以为其创建商品列表。 对于每件商品,您都可以定义下列信息:
- 唯一商品 ID(也称为 SKU)。
- 商品类型。
- 定价。
- 说明。
- Google Play 应如何处理和跟踪用户对该商品的购买。
如果您以相同价格出售多个应用或应用内商品,可以添加定价模板,从集中的位置来管理这些价格。 使用定价模板时,您可以在提供的价格中包含地方税,或者您也可以提供价格并让系统为这些价格添加地方税。 您可以对定价模板中的价格进行更改(例如更新一些国家/地区的汇率),您的更改会应用到与此模板关联的应用和应用内商品。
您还可以创建测试帐户,授权这些帐户测试尚未发布的应用。
要了解如何使用 Developer Console 配置您的应用内商品和商品列表,请参阅管理应用内购买结算 。
Google Play 购买流程
Google Play 使用的结账后端服务与用于应用购买的服务相同,因此您的用户将获得一致且熟悉的购买流程体验。
重要说明:您必须有 Google Payments 商家帐号才能在 Google Play 上使用应用内购买结算服务。
购买开始时,您的应用需要针对相应的应用内商品发送购买结算请求。 然后,Google Play 会处理此次交易的所有结账详情,包括请求和验证付款方式以及处理财务交易。
结账流程完成后,Google Play 会向您的应用发送购买详情,例如订单号、订单日期和时间以及所付价格。 您的应用从不需要处理任何财务交易,这些事宜完全由 Google Play 负责。
示例应用
为了帮助您将应用内购买结算集成到应用中,Android SDK 提供了一个示例应用,向您演示如何在应用内销售应用内商品和订阅。
适用于 Version 3 API 的 TrivialDrive 示例演示了如何使用 In-app Billing Version 3 API 在赛车游戏中实现应用内商品和订阅购买。 该应用不仅演示了如何发送应用内购买结算请求以及处理来自 Google Play 的同步响应, 还演示了如何通过此 API 记录商品的消耗情况。 版本 3 示例包括多种工具类,非常便于处理应用内购买结算操作和执行自动签名验证。
建议:请务必在发布应用前混淆其中的代码。 如需了解详细信息,请参阅安全性和设计。
混淆您的代码
您应混淆应用内购买结算代码,让攻击者难以对您的安全协议和其他应用组件进行反向工程。 我们建议您至少对代码运行 Proguard 等代码混淆工具。
除了运行代码混淆程序以外,我们还建议您使用以下技术混淆您的应用内购买结算代码。
- 将方法内嵌入其他方法中。
- 创建动态字符串,而不是将其定义为常量。
- 使用 Java 反射来调用方法。
使用这些技术有助于缩小应用的受攻击范围,并最大程度帮助您抵御会对应用内购买结算实现造成损害的攻击。
-keep class com.android.vending.billing.**
迁移注意事项
In-app Billing Version 2 API 已于 2015 年 1 月关闭。如果您现有的应用内购买结算实现使用的是 API 版本 2 或更低版本,则必须迁移到应用内购买结算版本 3。
迁移后,托管和未托管的商品处理方式如下:
- 您之前在 Developer Console 中定义的托管商品和订阅仍能使用版本 3。
- 对于您已经为现有应用定义的非托管商品,如果您使用 Version 3 API 针对这些商品发起购买请求,这些商品将被视为托管商品。 您无需在 Developer Console 中为这些商品创建新的商品条目,且能使用相同的商品 ID 来管理这些商品。
实现应用内购买结算
Google Play 上的应用内购买结算提供了一个直接、简单的界面,让您可以使用 Google Play 发送应用内购买结算请求和管理应用内购买结算交易。 下面的信息涵盖了如何使用 API 版本 3 从您的应用调用应用内购买结算服务的基本知识。
注:要查看完整实现并了解如何测试您的应用,请参阅出售应用内商品培训课程。 培训课程提供了一个完整的示例应用内购买结算应用,包括多种工具类,便于处理关键任务(例如设置您的连接、发送购买结算请求和处理来自 Google Play 的响应以及管理后台线程),这样您就可以从主 Activity 调用应用内购买结算。
开始前,请务必阅读应用内购买结算概览,以便熟悉一些概念,使您能够轻松实现应用内购买结算。
要在您的应用中实现应用内购买结算,您需要执行以下操作:
- 将应用内购买结算库添加到您的项目中。
- 更新您的
AndroidManifest.xml
文件。 - 创建
ServiceConnection
并将其绑定到IInAppBillingService
。 - 从您的应用发送应用内购买结算请求至
IInAppBillingService
。 - 处理来自 Google Play 的应用内购买结算请求响应。
将 AIDL 文件添加到您的项目中
IInAppBillingService.aidl
是一种定义应用内购买结算版本 3 服务接口的 Android 接口定义语言 (AIDL) 文件。 您可以使用此接口通过调用 IPC 方法调用来发送结算请求。
要获取 AIDL 文件,请执行以下操作:
- 打开 Android SDK 管理器。
- 在 SDK 管理器中,展开
Extras
部分。 - 选择 Google Play Billing Library。
- 点击 Install packages 完成下载。
IInAppBillingService.aidl
文件将安装到
。
要将 AIDL 添加到您的项目,请执行以下操作:
- 首先,下载 Google Play Billing Library 到您的 Android 项目:
- 选择 Tools > Android > SDK Manager。
- 在 Appearance & Behavior > System Settings > Android SDK 下面,选择 SDK Tools 标签以选择并下载 Google Play Billing Library。
- 接下来,复制
IInAppBillingService.aidl
文件到您的项目。- 如果您使用的是 Android Studio,请执行以下操作:
- 导航至 Project 工具窗口中的
src/main
。 - 选择 File > New > Directory,然后在 New Directory 窗口中输入
aidl
,再选择 OK。 - 选择 File > New > Package,然后在 New Package 窗口中输入
com.android.vending.billing
,再选择 OK。 - 使用您的操作系统文件资源管理器,导航至
,复制/extras/google/play_billing/ IInAppBillingService.aidl
文件,然后将其粘贴到项目中的com.android.vending.billing
软件包。
- 导航至 Project 工具窗口中的
- 如果您在非 Android Studio 环境中开发,请执行以下操作:创建目录
/src/com/android/vending/billing
,并将IInAppBillingService.aidl
文件复制到此目录。 将 AIDL 文件添加到您的项目中并使用 Gradle 工具构建项目,从而生成IInAppBillingService.java
文件。
- 如果您使用的是 Android Studio,请执行以下操作:
- 开发您的应用。您会在项目的
/gen
目录中看到名为IInAppBillingService.java
的生成文件。
更新您的应用清单
应用内购买结算依赖于 Google Play 应用,后者将处理应用与 Google Play 服务器之间的所有通信。 要使用 Google Play 应用,您的应用必须请求适当的权限。 您可以通过将 com.android.vending.BILLING
权限添加到 AndroidManifest.xml 文件执行此操作。 如果您的应用未声明应用内购买结算权限,但试图发送结算请求,Google Play 将拒绝请求并使用错误响应。
要为您的应用授予必要的权限,请在 AndroidManifest.xml
文件中添加以下代码行:
创建 ServiceConnection
您的应用必须拥有 ServiceConnection才能实现应用与 Google Play 之间的通信。 您的应用至少需要执行以下操作:
- 绑定到
IInAppBillingService
。 - 发送结算请求(作为 IPC 方法调用)至 Google Play 应用。
- 处理每个结算请求返回的同步响应消息。
绑定到 InAppBillingService
要在 Google Play 上与应用内购买结算服务建立连接,请实现 ServiceConnection
,以便将您的 Activity 绑定到 IInAppBillingService
。
建立连接后,重写 onServiceDisconnected(android.content.ComponentName))
和 onServiceConnected(android.content.ComponentName, android.os.IBinder))
方法以获取 IInAppBillingService
实例的引用。
IInAppBillingService mService;
ServiceConnection mServiceConn = new ServiceConnection()
{
@Override
public void onServiceDisconnected(ComponentName name)
{
mService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
mService = IInAppBillingService.Stub.asInterface(service);
}
};
在您 Activity 的 onCreate(android.os.Bundle))
方法中,通过调用 bindService(android.content.Intent,android.content.ServiceConnection,int))
方法执行绑定。 向方法传递引用应用内购买结算服务的 Intent(
和您创建的一个 ServiceConnection
实例,并明确地将 Intent 的目标软件包名称设置为 com.android.vending
— Google Play 应用的软件包名称。
注意:要保护结算交易的安全性,请始终确保使用下面示例中所示的 setPackage()(java.lang.String))
明确地将 Intent 的目标软件包名称设置为 com.android.vending
。 明确地设置软件包名称能够确保只有 Google Play 应用可以处理来自您的应用的结算请求,从而防止其他应用拦截这些请求。
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
serviceIntent.setPackage("com.android.vending");
bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
}
现在,您可以使用 mService 引用来与 Google Play 服务通信。
重要说明:完成您的 Activity
后,请务必与应用内购买结算服务解除绑定。 如果不解除绑定,开启的服务连接会导致您的设备性能下降。 此示例说明了如何通过重写 Activity 的 onDestroy()
方法对到应用内购买结算的服务连接 mServiceConn
执行解除绑定操作。
@Override public void onDestroy()
{
super.onDestroy();
if (mService != null)
{
unbindService(mServiceConn);
}
}
如需了解绑定到 IInAppBillingService
的服务连接的完整实现,请参阅[出售应用内商品]培训课程和相关示例。
发起应用内购买结算请求
将应用连接到 Google Play 后,您可以对应用内商品发送购买请求。 Google Play 为用户进入他们的付款方式提供了一个结账界面,这样您的应用就无需直接处理付款交易。 在商品被用户购买后,Google Play 会识别用户拥有此商品,并在此商品被消耗前阻止用户购买具有相同商品 ID 的另一商品。 您可以控制如何在应用中消耗商品,并通知 Google Play 该商品可供再次购买。 您也可以查询 Google Play,以便快速地检索用户的购买列表。 这样十分有用,例如,非常适合您希望在用户启动应用时恢复用户购买的情况。
查询可供购买的商品
在您的应用中,可以使用 In-app Billing Version 3 API 从 Google Play 查询商品详情。 要将请求传递至应用内购买结算服务,首先需要创建一个包含商品 ID 字符串 ArrayList
的 Bundle
,该字符串带有键“ITEM_ID_LIST”,每个字符串是可购买商品的商品 ID。
ArrayList skuList = new ArrayList ();
skuList.add("premiumUpgrade");
skuList.add("gas");
Bundle querySkus = new Bundle();
querySkus.putStringArrayList(“ITEM_ID_LIST”, skuList);
要从 Google Play 检索此信息,请在 In-app Billing Version 3 API 上调用 getSkuDetails
方法,然后将 In-app Billing API 版本(3)、发起调用的应用的软件包名称、商品类型(应用内)以及您创建的 Bundle
传递给方法。
Bundle skuDetails = mService.getSkuDetails(3, getPackageName(), "inapp", querySkus);
如果请求成功,返回的 Bundle
将包含响应代码 BILLING_RESPONSE_RESULT_OK
(0)。
警告:请不要在主线程上调用 getSkuDetails
方法。 调用此方法会触发网络请求,进而阻塞主线程。 请创建单独的线程并从该线程内部调用 getSkuDetails
方法。
要从 Google Play 查看所有可能的响应代码,请参阅应用内购买结算参考。
查询结果将保存在带有键 DETAILS_LIST
的字符串 ArrayList 中。购买信息存储在 JSON 格式的字符串中。 要查看返回的商品类型详细信息,请参阅应用内购买结算参考。
在此示例中,您将从之前代码段返回的 skuDetails Bundle 中检索您的应用内商品的价格。
int response = skuDetails.getInt("RESPONSE_CODE");
if (response == 0) {
ArrayList responseList = skuDetails.getStringArrayList("DETAILS_LIST");
for (String thisResponse : responseList) {
JSONObject object = new JSONObject(thisResponse);
String sku = object.getString("productId");
String price = object.getString("price");
if (sku.equals("premiumUpgrade"))
mPremiumUpgradePrice = price;
else if (sku.equals("gas"))
mGasPrice = price;
}
}
购买商品
要从您的应用发起购买请求,请在应用内购买结算服务上调用 getBuyIntent
方法。 将 In-app Billing API 版本(3)、发起调用的应用的软件包名称、要购买商品的商品 ID、商品类型(应用内或订阅)以及 developerPayload
字符串传递给方法。 developerPayload
字符串用于指定您想要 Google Play 随购买信息一同发送的任何其他参数。
Bundle buyIntentBundle = mService.getBuyIntent(3, getPackageName(), sku, "inapp", "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");
如果请求成功,返回的 Bundle 将包含响应代码 BILLING_RESPONSE_RESULT_OK
(0) 和您可以用于开始购买流程的 PendingIntent。接下来,请使用键 BUY_INTENT
从响应 Bundle
中提取 `PendingIntent。
PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");
要完成购买交易,请调用 startIntentSenderForResult(android.content.IntentSender,int,android.content.Intent,int,int,int))
方法并使用您创建的 PendingIntent
。 在此示例中,您将任意值 1001 用于请求代码。
startIntentSenderForResult(pendingIntent.getIntentSender(), 1001, new Intent(), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0));
Google Play 会将对您 PendingIntent
的响应发送至应用的 onActivityResult((int,int,android.content.Intent))
方法。 onActivityResult(int,int,android.content.Intent))
方法将获得结果代码 Activity.RESULT_OK
(1) 或 Activity.RESULT_CANCELED
(0)。
订单的购买数据是 JSON 格式的字符串,将映射到响应 Intent 中的 INAPP_PURCHASE_DATA
键,例如:
{
"orderId":"GPA.1234-5678-9012-34567",
"packageName":"com.example.app",
"productId":"exampleSku",
"purchaseTime":1345678900000,
"purchaseState":0,
"developerPayload":"bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ",
"purchaseToken":"opaque-token-up-to-1000-characters" }
注:Google Play 会为购买生成令牌。此令牌是不透明的字符序列,最长可为 1,000 字符。 将整个令牌传递至其他方法(例如在您消耗购买时,如消耗购买(https://developer.android.com/training/in-app-billing/purchase-iab-products.html?hl=zh-cn#Consume)中所述)。 不要省略或者截断此令牌,您必须保存并返回整个令牌。
继续前面的示例,您将从响应 Intent获得响应代码、购买数据和签名。
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1001) {
int responseCode = data.getIntExtra("RESPONSE_CODE", 0);
String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
if (resultCode == RESULT_OK) {
try {
JSONObject jo = new JSONObject(purchaseData);
String sku = jo.getString("productId");
alert("You have bought the " + sku + ". Excellent choice,adventurer!");
} catch (JSONException e) {
alert("Failed to parse purchase data.");
e.printStackTrace();
}
}
}
}
安全性建议:在您发送购买请求时,请创建一个可以对此购买请求进行唯一标识的字符串令牌并在 developerPayload
中包含此令牌。您可以将随机生成的字符串作为令牌。 从 Google Play 接收到购买响应时,请确保检查返回的数据签名、orderId
和 developerPayload
字符串。 为了增强安全性,您应在自己安全的服务器上执行检查。 请确保验证 orderId
为您之前未处理的唯一值,且 developerPayload
字符串与您之前通过购买请求发送的令牌相匹配。
查询已购买商品
要从您的应用检索用户所发起购买的相关信息,请在应用内购买结算版本 3 服务上调用 getPurchases
方法。 将 In-app Billing API 版本(3)、发起调用的应用的软件包名称以及商品类型(应用内或订阅)传递给方法。
Bundle ownedItems = mService.getPurchases(3, getPackageName(), "inapp", null);
Google Play 服务仅会返回由当前登录设备的用户帐户发起的购买。 如果请求成功,返回的 Bundle
将包含响应代码 0。响应 Bundle
也会包含商品 ID 列表、每个购买的订单详情列表以及每个购买的签名。
为了提升性能,第一次调用 getPurchase
时,应用内购买结算服务仅会返回由用户拥有的最多 700 个商品。 如果用户拥有大量商品,Google Play 会在响应 Bundle
中包含映射到键 INAPP_CONTINUATION_TOKEN
的字符串令牌,以表明可以检索更多的商品。 然后,您的应用可以进行后续 getPurchases
调用,并将此令牌作为参数传递。 Google Play 会继续在响应 Bundle
中返回继续令牌,直到用户拥有的所有商品都发送到您的应用。
如需了解有关由 getPurchases
返回的数据的详细信息,请参阅应用内购买结算参考。 下面的示例说明了如何从响应中检索此数据。
int response = ownedItems.getInt("RESPONSE_CODE");
if (response == 0) {
ArrayList ownedSkus = ownedItems.getStringArrayList("INAPP_PURCHASE_ITEM_LIST");
ArrayList purchaseDataList = ownedItems.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
ArrayList signatureList = ownedItems.getStringArrayList("INAPP_DATA_SIGNATURE_LIST");
String continuationToken = ownedItems.getString("INAPP_CONTINUATION_TOKEN");
for (int i = 0; i < purchaseDataList.size(); ++i) {
String purchaseData = purchaseDataList.get(i);
String signature = signatureList.get(i);
String sku = ownedSkus.get(i);
// do something with this purchase information
// e.g. display the updated list of products owned by user
}
// if continuationToken != null, call getPurchases again
// and pass in the token to retrieve more items
}
消耗购买
您可以使用 In-app Billing Version 3 API 跟踪在 Google Play 中购买的应用内商品的所有权。 应用内商品一经购买,就会被视为“被拥有”且无法从 Google Play 购买。 您必须对应用内商品发送消耗请求,然后 Google Play 才能允许再次购买。
重要说明:可以消耗托管的应用内商品,但不能消耗订阅。
如何在应用中使用消耗机制取决于您。通常情况下,您可以对用户想要购买多次、能够提供短期效益的应用内商品实现消耗(例如,游戏中使用的货币或设备)。 您通常不必对仅供购买一次和具有永久效应的应用内商品实现消耗(例如,高级版升级)。
要记录购买消耗,请将 consumePurchase
方法发送到应用内购买结算服务并在标识要移除购买的 purchaseToken
字符串值中传递。 purchaseToken
是由购买请求成功后 Google Play 服务在 INAPP_PURCHASE_DATA
字符串中所返回数据的一部分。 在此示例中,您会将使用 purchaseToken
标识的商品的消耗记录在 token
变量中。
int response = mService.consumePurchase(3, getPackageName(), token);
警告:请不要在主线程上调用 consumePurchase
方法。 调用此方法会触发网络请求,进而阻塞主线程。 请创建单独的线程并从该线程内部调用 consumePurchase
方法。
您负责控制和跟踪如何向用户配置应用内商品。 例如,如果用户购买了游戏内货币,您应使用购买的货币金额更新玩家的库存。
安全性建议:您必须首先发送消耗请求,才能向用户配置可消耗的应用内购买商品。 确保已从 Google Play 接收到成功的消耗请求,然后再配置商品。
实现订阅
启动订阅的购买流程与启动商品的购买流程相似,不同之处是商品类型必须设置为“订阅”。 购买结果会传送至您 Activity 的onActivityResult(int,int,android.content.Intent))
方法,与应用内商品的情况完全一样。
Bundle bundle = mService.getBuyIntent(3, "com.example.myapp", MY_SKU, "subs", developerPayload);
PendingIntent pendingIntent = bundle.getParcelable(RESPONSE_BUY_INTENT);
if (bundle.getInt(RESPONSE_CODE) == BILLING_RESPONSE_RESULT_OK)
{
// Start purchase flow (this brings up the Google Play UI).
// Result will be delivered through onActivityResult().
startIntentSenderForResult(pendingIntent, RC_BUY, new Intent(), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0));
}
要查询有效订阅,请使用 getPurchases
方法,并将商品类型参数设置为“订阅”。
Bundle activeSubs = mService.getPurchases(3, "com.example.myapp", "subs", continueToken);
调用会返回 Bundle
,其包含由用户拥有的所有有效订阅。 如果订阅到期且不续订,将不会出现在返回的 Bundle
中。
保证您的应用安全
为了确保发送到您应用的交易信息的完整性,Google Play 会签署包含购买订单响应数据的 JSON 字符串。 Google Play 会使用 Developer Console 中与您的应用关联的私钥来创建此签名。 Developer Console 会为每个应用生成一个 RSA 密钥对。
注:要找到此密钥对的公钥部分,请在 Developer Console 中打开应用的详细信息,然后点击 Services & APIs,并查看命名为 Your License Key for This Application 的字段。
由 Google Play 生成的以 Base64 编码的 RSA 公钥为二进制编码,格式为 X.509 subjectPublicKeyInfo DER SEQUENCE。 它与 Google Play 许可使用的公钥相同。