适用于Android的DRM
DRM(数字版权管理,也常被称为许可证验证)用于解决开发者对未经授权复制和分发应用的后顾之忧。如果在应用中实现DRM,就能确保只有购买应用的用户可以在授权的设备上安装该应用。
许可证检查概述
通过DRM API可以检查用户是否获得了内容许可证。亚马逊应用商店客户端会在应用的本地缓存中查找相应的内容许可证。如果在本地缓存中找到了许可证,则会在响应中将其返回。(因此,即使用户处于离线状态,应用仍然可以运行。) 如果缓存中没有许可证,亚马逊应用商店客户端将调用Appstore,以检索内容许可证。
您需要使用DRM API启动许可证检查,然后根据亚马逊返回的许可证状态应用逻辑,对用户进行授权或予以拒绝。
Appstore SDK中的DRM
以前,将Android APK上传至亚马逊应用商店后,可以为“应用亚马逊DRM?”选择是或否。如果选择是,则亚马逊会为您的应用添加DRM。
使用Appstore SDK,开发者控制台不会再显示此选项。如果想要为APK添加DRM,请使用DRM API(包含在Appstore SDK中)在您的应用中引入许可证检查。
如果尚未升级为Appstore SDK,但使用了较早的IAP SDK版本(或者没有使用IAP),则上传APK后,系统会显示 “是否允许亚马逊应用DRM?”选项。
警告消息
如果上传的APK使用了较早的IAP SDK版本或者根本没有使用SDK,则显示以下警告。
DRM示例应用
提供了DRM示例应用和教程,通过简单的集成展示了DRM API代码。
在应用中实现DRM
要在应用中实现DRM,请执行以下操作:
-
按照集成Appstore SDK中的说明,将Appstore SDK添加到您的Android项目中。
- 更新应用的清单文件。
-
向清单中添加
ResponseReceiver
的条目。以下代码示例展示了如何在DRM的AndroidManifest.xml文件中添加ResponseReceiver
。如果您的应用以Android 12或更高版本为目标,则必须在MainActivity
和ResponseReceiver
中显式地将android:exported
设置为true
,如下面的示例所示:<application> ... <activity android:label="@string/app_name" android:name="com.amazon.sample.drm.MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name = "com.amazon.device.drm.ResponseReceiver" android:exported="true" android:permission = "com.amazon.drm.Permission.NOTIFY" > <intent-filter> <action android:name = "com.amazon.drm.NOTIFY" /> </intent-filter> </receiver> ... </application>
-
如果您的应用以Android API级别30或更高级别为目标,则必须在AndroidManifest.xml文件中定义应用需要查询的程序包列表。要想能够查询Amazon App Tester和亚马逊应用商店,请将以下代码添加到您的清单文件中。
<manifest> ... <queries> <package android:name="com.amazon.sdktestclient" /> <package android:name="com.amazon.venezia" /> </queries> </manifest>
-
-
调用
verifyLicense()
,启动许可证验证。此方法已在LicensingService
类中公开。它将两个参数作为输入:ApplicationContext
LicensingListener
的实现
当应用启动时,启动许可证验证。可以使用以下任一方法启动许可证验证:
MainActivity
的onCreate()
方法Application
类自定义实现中的onCreate()
示例如下:
LicensingService.verifyLicense(getApplicationContext(), new LicenseVerificationCallback(this));
提示:LicensingService
类提供方法getAppstoreSDKMode()
来确定应用是处于SANDBOX
模式还是PRODUCTION
模式。这在使用Amazon App Tester对应用进行测试时非常有用,因为Amazon App Tester要求应用处于沙盒模式。如果没有先调用verifyLicense()
,则getAppstoreSDKMode()
方法会返回UNKNOWN
。 -
实现
LicensingListener
。LicensingListener
定义单一方法:onLicenseCommandResponse(final LicenseResponse licenseResponse)
。在收到来自亚马逊应用商店verifyLicense()
调用的结果后,Appstore SDK会调用此方法。LicenseResponse
将包含verifyLicense()
调用的状态。响应将包含下列状态之一:LICENSED
NOT_LICENSED
ERROR_VERIFICATION
ERROR_INVALID_LICENSING_KEYS
EXPIRED
UNKNOWN_ERROR
有关每种状态和原因的描述,请参阅许可证状态。
LicensingListener
接口的基本实现方法如下所示。(此代码仅记录许可证的返回状态。)public class LicenseVerificationCallback implements com.amazon.device.drm.LicensingListener { public void onLicenseCommandResponse(final LicenseResponse licenseResponse) { final LicenseResponse.RequestStatus status = licenseResponse.getRequestStatus(); Log.d(TAG, "onLicenseCommandResponse: RequestStatus (" + status + ")"); switch (status) { case LICENSED: Log.d(TAG, "onLicenseCommandResponse: LICENSED"); break; case NOT_LICENSED: Log.d(TAG, "onLicenseCommandResponse: NOT_LICENSED"); break; case ERROR_VERIFICATION: Log.d(TAG, "onLicenseCommandResponse: ERROR_VERIFICATION"); break; case ERROR_INVALID_LICENSING_KEYS: Log.d(TAG, "onLicenseCommandResponse: ERROR_INVALID_LICENSING_KEYS"); break; case EXPIRED: Log.d(TAG, "onLicenseCommandResponse: EXPIRED"); break; case UNKNOWN_ERROR: Log.d(TAG, "onLicenseCommandResponse: ERROR"); } } }
提示: DRM示例应用中提供了一个实现方法示例。
许可证状态
在调用verifyLicense()
时,许可证服务会发回下表中定义的许可证状态之一。
许可证状态 | 描述 |
---|---|
LICENSED |
用户拥有有效的许可证。 |
NOT_LICENSED |
用户没有有效的许可证。用户无权使用该应用。 |
ERROR_VERIFICATION |
尝试验证许可证时出错。验证错误可能由以下原因造成:
|
ERROR_INVALID_LICENSING_KEYS |
用户拥有许可证密钥,但密钥无效。许可证密钥无效可能由以下原因造成:
|
EXPIRED |
用户的许可证已过期,用户当前的许可证无效。许可证有效期为60天。30天后,亚马逊应用商店每24小时会尝试一次续订许可证。 如果用户离线超过60天,则亚马逊应用商店将无法在许可证过期之前完成续订。如果许可证过期,客户将无法再启动该应用。 许可证过期也可能由以下原因造成:
|
UNKNOWN_ERROR |
此状态表示亚马逊端出现了内部错误。 |
DRM库混淆处理
Appstore SDK库中的大部分内容已经过混淆处理(在打包到JAR前)。但是,一些面向开发者的类不会进行混淆处理。以下DRM库的类不会进行混淆处理:
LicensingListener
LicensingService
LicenseResponse
RequestId
如果想要防止混淆处理这些类别,请在ProGuard文件中添加适当的引用以将其排除(假设您使用ProGuard对代码进行混淆处理)。
Last updated: 2024年12月4日