当您为亚马逊设备构建应用时,很容易认为亚马逊Fire平板电脑和亚马逊Fire TV之间在盈利方面的最大差异在于设备类型。没错,电视应用依赖于遥控导航,适合远距离坐着观看,而平板电脑应用则是为触摸和移动使用而设计。但论及盈利,更有意义的区别不在于设备,而在于您提供的应用类型。
使用流媒体视频应用的用户的需求、期望和行为与使用非流媒体应用(如游戏、实用工具或教育工具)的用户有着本质上的不同。流媒体应用通常是为持续、被动的参与而构建的。它们旨在帮助用户发现和消费长篇视频内容,用户通常是坐在沙发上进行这些活动。相比之下,非流媒体应用为交互式,并且以任务为导向 - 无论是完成游戏关卡、查看待办事项列表还是解决谜题,都是如此。
这种区别直接影响您应当采用的盈利方式。在本文中,我们将回顾常见的盈利方式,介绍一些场景,助您确保盈利策略适合自己正在开发的应用类型,然后会讨论如何使用应用统计信息报表来优化收入和留存率。
在深入探讨具体的实现示例之前,了解亚马逊应用商店可供您使用的主要盈利选项会很有帮助。尽管每个应用都有独特的需求,但大多数盈利策略都属于以下类别之一。
应用内购买是最为灵活的盈利选项之一。通过该方式,您可以提供:
亚马逊IAP集成适用于流媒体和非流媒体应用。
广告可以通过第三方广告服务中受支持的SDK来集成。广告的形式包括横幅广告、奖励视频和间隙或片前视频布置。此选项非常适合用户会话频繁的免费应用。
您可以要求用户预付费用后才能安装应用,而不是通过IAP盈利。如果您的价值主张一目了然,不需要持续的内容更新或追加销售时,这种方式最有效。但是,如果您的应用存在不可解锁或重复出现的内容,IAP可能更为合适。
通过Merch on Demand(仅提供英文版),您可以直接通过自己的应用提供品牌化实体产品,如衬衫、杯子或配饰。这是一种建立品牌参与度的好方法,特别是在您的应用拥有忠实或小众的受众时。
您还可以使用产品广告API(仅提供英文版)将您的应用链接到亚马逊的零售目录。这对于与实物商品相关的应用(如健身、烹饪或科技)很有用,可以让您展示相关的产品信息并获得推广收入。
要采用这种盈利方式,您需要有一个亚马逊推广联盟账户,并且您的应用必须符合资格要求。
具体该如何在应用中构建盈利方式? 这里有四个实际场景,展示了如何在流媒体和非流媒体应用中实现应用内购买 (IAP) 策略和非IAP策略。
每个示例都包括一个简短用例,说明该策略适用的原因,以及使其发挥作用所需关键实现步骤的简要介绍。无论您是通过付费应用、应用内购买还是广告来盈利,这些模式都可以帮助您设计自己的盈利计划,并充满信心地开始编码。
您正在开发一款健身流媒体应用,该应用在Fire TV和Fire平板电脑上都可使用,提供视频健身目录。有些内容为免费提供,但高级锻炼计划,如多周计划或专门训练系列,只对付费用户开放。用户要获得访问权限,可以使用亚马逊应用商店IAP设置,直接通过应用来订阅。
流媒体应用通常会吸引那些长时间观看并定期回来观看新内容的用户。当内容属于专门内容或频繁更新时,如指导性锻炼、健康系列或教学课程,订阅可以让您轻松地为高级内容设置门槛,同时有助于确保用户保留率。有限的免费内容有利于激发用户对更多内容的兴趣,并鼓励订阅。
使用亚马逊的应用内购买 (IAP) SDK,您可以提供跨Fire TV和Fire平板电脑设备生效的基于订阅的访问权限。基于订阅的应用盈利由亚马逊应用商店管理,让开发者更容易处理账单和续订。
首先,您需要在开发者控制台中定义订阅SKU。管理应用时,导航到应用内商品,然后单击添加新的IAP。
为订阅指定标题和SKU。单击确认。
然后在您的应用代码中,实现Appstore SDK IAP。这主要涉及使用PurchasingService和PurchasingListener与亚马逊就应用内购买进行通信。
在AndroidManifest.xml文件中添加ResponseReceiver。例如:
<application>
…
<receiver
android:name="com.amazon.device.iap.ResponseReceiver"
android:permission="com.amazon.inapp.purchasing.Permission.NOTIFY"
android:exported="true">
<intent-filter>
<action android:name="com.amazon.inapp.purchasing.NOTIFY" />
</intent-filter>
</receiver>
</application>
在MainActivity.kt文件的onResume方法中,向PurchasingService注册PurchasingListener实现。然后,使用getUserData 获取用户特定的数据,并使用getPurchaseUpdates恢复任何活跃订阅。后一步对于应用重新安装或用户从新设备访问其订阅等场景至关重要。
override fun onCreate(savedInstanceState: Bundle?) {
…
myListener = MyPurchasingListener()
…
}
…
override fun onResume() {
super.onResume()
PurchasingService.registerListener(this.applicationContext, myListener)
PurchasingService.getUserData()
PurchasingService.getPurchaseUpdates(false)
}
PurchasingListener接口需要实现多个处理程序,用于处理来自亚马逊应用商店的异步响应。最为重要的是,您将需要实现onUserDataResponse、onProductDataResponse、onPurchaseResponse以及onPurchaseUpdateResponse。
class MyPurchasingListener : PurchasingListener {
override fun onUserDataResponse(response: UserDataResponse) {
// 在对于 [PurchasingService.getUserData] 的响应上调用
}
override fun onProductDataResponse(response: ProductDataResponse) {
// 在对于 [PurchasingService.getProductData] 的响应上调用
}
override fun onPurchaseResponse(response: PurchaseResponse) {
// 在对于 [PurchasingService.purchase] 的响应上调用
}
override fun onPurchaseUpdatesResponse(response: PurchaseUpdatesResponse)
{
// 在对于 [PurchasingService.getPurchaseUpdates] 的响应上调用
}
例如,处理getProductData调用将涉及:
override fun onProductDataResponse(response: ProductDataResponse) {
val requestStatus: ProductDataResponse.RequestStatus = response.requestStatus
when (requestStatus) {
ProductDataResponse.RequestStatus.SUCCESSFUL -> {
Log.i(TAG, "ProductDataResponse成功")
response.productData.forEach { sku, product ->
Log.d(TAG, "产品:SKU:$sku,类型:${product.productType},标题:${product.title},描述:${product.description},价格:${product.price},SmallIconUrl:${product.smallIconUrl}")
// 使用产品信息来更新应用的用户界面
}
// 检查是否有任何已请求但不可用的SKU。
val unavailableSkus: Set<String> = response.unavailableSkus
if (unavailableSkus.isNotEmpty()) {
Log.w(TAG, "不可用的SKU:$unavailableSkus。这些SKU可能无效或未在开发者控制台中正确发布。")
}
// 根据此数据对可用产品启用购买按钮。
}
ProductDataResponse.RequestStatus.FAILED -> {
Log.e(TAG, "ProductDataResponse失败。无法检索信息。")
}
ProductDataResponse.RequestStatus.NOT_SUPPORTED -> {
Log.w(TAG, "ProductDataResponse不受支持。IAP可能不可用。")
}
else -> {
Log.w(TAG, "ProductDataResponse: 未处理状态:$requestStatus")
}
}
}
当对PurchasingService.purchase进行调用时,使用onPurchaseResponse处理程序检索有关已完成购买的信息,验证购买,然后将高级内容访问权限授予用户。
override fun onPurchaseResponse(response: PurchaseResponse) {
val requestStatus: PurchaseResponse.RequestStatus = response.requestStatus
when (requestStatus) {
PurchaseResponse.RequestStatus.SUCCESSFUL -> {
val receipt: Receipt? = response.receipt
if (receipt != null) {
Log.i(TAG, "PurchaseResponse成功。收据ID:${receipt.receiptId},SKU: ${receipt.sku},购买日期:${receipt.purchaseDate},取消日期: ${receipt.cancelDate}")
// 重要须知:在此处执行服务器端收据验证。
// 实现将高级内容访问权限授予用户的逻辑。
Log.i(TAG, "购买SKU ${receipt.sku}成功。")
if (receipt.isCanceled) {
// 此状态表示购买已作废(例如,由亚马逊支持部门作废)。这对于新的成功购买来说很少见。
Log.w(TAG, "在onPurchaseResponse中标记为已取消的购买:${receipt.receiptId}。在RVS确认取消后,应撤销权利。")
// 实现将高级内容访问权限撤销的逻辑
}
} else {
Log.e(TAG, "PurchaseResponse成功,但收据为空。不应当发生这种情况。")
}
}
PurchaseResponse.RequestStatus.FAILED -> {
// 购买尝试失败(例如,由于付款问题、用户取消)。
Log.e(TAG, "PurchaseResponse失败。不授予权利。")
// 将购买失败的情况通知用户。
// 也可提供原因(如果有)或指导。
}
PurchaseResponse.RequestStatus.ALREADY_PURCHASED -> {
// 此状态表示用户已拥有此活跃订阅。
// 这不一定是错误。
// 确保用户具备内容的访问权限。
Log.i(TAG, "PurchaseResponse:SKU ${response.receipt?.sku}已购买。")
// 确认订阅已激活。
// 这可能涉及检查本地缓存或使用getPurchaseUpdates或收据验证服务重新验证。
// 必要时刷新用户界面以反映拥有状态。
}
PurchaseResponse.RequestStatus.INVALID_SKU -> {
// 购买调用中提供的SKU无效或亚马逊无法识别。
Log.e(TAG, "PurchaseResponse:无效SKU。SKU:${response.receipt?.sku}。检查亚马逊开发者控制台中的SKU定义和应用代码。")
}
PurchaseResponse.RequestStatus.NOT_SUPPORTED -> {
// 购买操作不受支持。
Log.w(TAG, "PurchaseResponse不受支持。IAP可能不可用。")
}
else -> {
Log.w(TAG, "PurchaseResponse:未处理状态:$requestStatus")
}
}
}
请注意,应通过收据验证服务 (RVS) 验证购买来处理SUCCESSFUL响应状态。收据对象 (response.receipt) 包含购买令牌 (receipt.receiptId) 和其他详细信息。此信息必须发送到您的后端服务器,然后该服务器将使用它通过RVS向亚马逊验证购买。这样可以防止客户端篡改,并确认购买合法。
验证购买的服务器端逻辑涉及:
1. 应用将receipt.receiptId和response.userData.userId 发送到安全后端服务器。
2. 服务器调用RVS,路径基于开发者的共享密钥、客户的用户ID和购买收据ID。例如:
https://appstore-sdk.amazon.com/version/1.0/verifyReceiptId/developer/REPLACE-WITH-SHARED-SECRET/user/REPLACE-WITH-USER-ID/receiptID/REPLACE-WITH-RECEIPT_ID
3. 成功响应RVS后,您将在数据库中记录购买和订阅状态,此时要确保存储receipt.startDate和receipt.endDate。
4. 您向应用发送解锁高级内容的信号(通过安全的API或推送通知)。
在MainActivity定义中,您将调用PurchasingService.getProductData,根据其SKU检索有关特定订阅IAP商品的信息。例如:
fun fetchSubscriptionProductData() {
Log.d(TAG, "获取订阅的产品数据。")
val subscriptionSkus: MutableSet<String> = HashSet()
subscriptionSkus.add("subscription_mo_ptp_01")
subscriptionSkus.add("subscription_yr_ptp_02")
PurchasingService.getProductData(subscriptionSkus)
}
发起购买的示例如下:
fun initiatePurchase(sku: String) {
if (sku.isBlank()) {
Log.e(TAG, "SKU不能为空方可发起购买。")
return
}
Log.d(TAG, "尝试对该SKU发起购买:$sku")
PurchasingService.purchase(sku)
}
实现流媒体应用订阅盈利在技术上较简单,在策略上也较合理。它自然地与用户参与视频内容的方式(即定期返回以获得持续价值)相符,并为开发者提供与有意义的用户意图相关的可靠、经常性收入流。
您正在为Fire平板电脑构建一个休闲益智游戏。游戏的核心玩法是免费的,但玩家可以通过购买奖励生命、提示包或装饰物品来增强其体验。这些购买也通过SDK IAP进行。非订阅IAP商品要么是消费品(一次性使用,如额外生命),要么是权利(永久解锁,如新角色皮肤)。
非流媒体应用,尤其是游戏,往往会促使玩家进行短暂、频繁的会话,促进对活跃任务的深度参与。这种行为非常容易发生冲动性购买,通过购买来实现即时奖励或加快进度。通过消费品和权利,您可以通过这些微时刻盈利,而无需将核心功能置于付费墙之后。
与设置IAP订阅商品类似,您可以在开发者控制台中添加IAP商品,根据需要选择消费品或权利。
对于每个商品,指定标题和SKU。例如:
与订阅IAP商品类似,为消费品和权利实现IAP涉及实现和注册PurchasingListener来处理因调用PurchasingService而产生的响应。
然而,使用消费品与订阅不同,因为当商品“已交付”给用户时,应调用PurchasingService.notifyFullfillment()。这会将商品已提供的情况通知亚马逊,允许用户再次购买相同的消费品SKU。侦听器还应通过尝试履行在onPurchaseUpdatesResponse中发现的未履行消费品来处理这些消费品,确保即使应用在履行之前关闭,也能将商品授予用户。
例如,在PurchasingListener实现中,您应该有一个处理履行的方法。
private fun fulfillConsumable(receipt: Receipt) {
val sku: String = receipt.sku
val receiptId: String = receipt.receiptId
Log.i(TAG, "尝试履行SKU:$sku,其收据ID为:$receiptId")
// 从概念上讲,在这里将商品交付给用户。
// 例如,递增提示、生命等的计数器。
// 将商品已履行的情况通知亚马逊。
PurchasingService
.notifyFulfillment(receiptId, FulfillmentResult.FULFILLED)
Log.i(TAG, "已对该收据ID调用notifyFulfillment:$receiptId,其状态为FULFILLED")
}
一旦验证了收据,onPurchaseResponse处理程序就会调用函数fulfillConsumable。
override fun onPurchaseResponse(response: PurchaseResponse) {
val skuFromReceipt: String = response.receipt?.sku ?: "N/A"
when (response.requestStatus) {
PurchaseResponse.RequestStatus.SUCCESSFUL -> {
response.receipt?.let { currentReceipt ->
val successMsg: String = "该SKU的购买结果为SUCCESSFUL:${currentReceipt.sku}. ReceiptId: ${currentReceipt.receiptId}"
if (currentReceipt.productType == ProductType.CONSUMABLE) {
fulfillConsumable(currentReceipt)
} else {
// 处理其他类型的IAP
}
} ?: run {
val errorMsg: String = "购买成功,但收据为空。不应当发生这种情况。"
Log.e(TAG, errorMsg)
}
}
PurchaseResponse.RequestStatus.FAILED -> {
val failedMsg: String = "该SKU的购买结果为FAILED:$skuFromReceipt。请检查日志。"
Log.e(TAG, failedMsg)
}
PurchaseResponse.RequestStatus.ALREADY_PURCHASED -> {
val alreadyPurchasedMsg: String = "该SKU的购买结果为ALREADY_PURCHASED:$skuFromReceipt。"
Log.w(TAG, alreadyPurchasedMsg)
response.receipt?.let { currentReceipt ->
if (currentReceipt.productType == ProductType.CONSUMABLE) {
fulfillConsumable(currentReceipt)
}
}
}
PurchaseResponse.RequestStatus.INVALID_SKU -> {
val invalidSkuMsg: String = "购买结果为INVALID_SKU:$skuFromReceipt。请在开发者控制台中检查SKU。"
Log.w(TAG, invalidSkuMsg)
}
PurchaseResponse.RequestStatus.NOT_SUPPORTED -> {
val notSupportedMsg: String = "购买结果为NOT_SUPPORTED。请检查设备功能或IAP设置。"
Log.w(TAG, notSupportedMsg)
}
PurchaseResponse.RequestStatus.PENDING -> {
val pendingMsg: String = "该SKU的购买结果为SKU:$skuFromReceipt。正在等待解决(例如家长批准)。"
Log.i(TAG, pendingMsg)
// 通常,应用不会在此处采取任何行动。亚马逊
// 应用商店将处理待处理状态,在解决问题之后
// 会将新的onPurchaseResponse或onPurchaseUpdatesResponse
// 发出。
}
null -> {
val nullMsg: String = "PurchaseResponse status is NULL (or unhandled). This should not happen."
Log.e(TAG, nullMsg)
}
}
}
通过IAP添加消费品或权利是一种灵活且用户友好的非流媒体应用盈利方式。它与用户行为相符,保持核心体验的可访问性,并让用户可以选择为有意义的游戏内(或应用内)优势或定制内容付费。
您正在开发一款生产力应用,例如一款焦点式任务管理器或有指导的日记应用。该应用可以免费使用,但您希望通过展示奖励视频广告来盈利。例如,用户可以通过观看广告来解锁高级模板或解除每日使用上限。为此,您需要集成受支持的第三方广告SDK(如Chartboost或AdColony)。
非流媒体应用通常涉及短暂而频繁的会话,这使它们很适合不会打断长篇内容的奖励或间隙广告。通过奖励视频,用户可以获得明确的价值,以此换取观看时间,开发者可以在不增加付费墙的情况下实现盈利。这种模式在重复使用很常见的实用工具和休闲应用类别中尤其有效。
首先选择亚马逊支持的广告SDK。对于以下示例,我们将使用Chartboost Android SDK。
在您的应用中,实现一个导入Chartboost SDK的新Activity (例如RewardedAdsActivity.kt)。
import com.chartboost.sdk.Chartboost
import com.chartboost.sdk.ads.Rewarded
import com.chartboost.sdk.LoggingLevel
import com.chartboost.sdk.events.*
import com.chartboost.sdk.callbacks.RewardedCallback
import com.chartboost.sdk.privacy.model.DataUseConsent
在RewardedAdsActivity的onCreate函数中,初始化SDK。
// 替换为您实际的Chartboost应用ID和应用签名
private val chartboostAppID: String = "CHARTBOOST_APP_ID"
private val chartboostAppSignature: String = "CHARTBOOST_APP_SIGNATURE"
// 为奖励广告定义默认位置
const val REWARDED_AD_LOCATION = "default-rewarded_video"
…
override fun onCreate(savedInstanceState: Bundle?) {
…
// 一定要注意在初始化SDK之前设置数据使用同意。
// 在实际应用中,这将基于用户同意。
// 对于此例,我们将使用占位符。
Chartboost.addDataUseConsent(this, DataUseConsent.GDPR("1"))
Chartboost.addDataUseConsent(this, DataUseConsent.CCPA("1---"))
// 启用详细日志记录。在startWithAppId之前调用此项。
Chartboost.setLoggingLevel(LoggingLevel.ALL)
Chartboost.startWithAppId(
applicationContext, chartboostAppID, chartboostAppSignature
) { startError ->
if (startError == null) {
val message = "Chartboost SDK成功初始化。
Log.d("ChartboostInit", message)
// 初始化成功后预缓存广告
loadRewardedAd()
} else {
val errorMessage = "Chartboost SDK初始化失败:${startError.code.name}"
Log.e("ChartboostInit", errorMessage)
}
}
}
…
奖励广告展示前必须进行缓存,因此需要实现广告的加载和缓存机制。在RewardedAdsActivity中定义的以下函数演示了如何做到这一点。
private fun loadRewardedAd() {
if (rewardedAd == null || !rewardedAd!!.isCached()) {
createAndCacheRewardedAd()
} else {
Log.d("ChartboostRewarded", "$REWARDED_AD_LOCATION的奖励广告已缓存。")
showAdButton.isEnabled = true
}
}
private fun createAndCacheRewardedAd() {
rewardedAd = Rewarded(REWARDED_AD_LOCATION, object : RewardedCallback {
override fun onAdLoaded(event: CacheEvent, error: CacheError?) {
if (error != null) {
val errorMessage = "对于位置 ${event.ad.location},奖励广告加载失败:${error.code.name}"
Log.e("ChartboostRewarded", errorMessage)
showAdButton.isEnabled = false
} else {
Log.d("ChartboostRewarded", "奖励广告对于位置${event.ad.location}成功加载。")
showAdButton.isEnabled = true
}
}
override fun onAdRequestedToShow(event: ShowEvent) {
Log.d("ChartboostRewarded", "已请求对位置${event.ad.location}显示奖励广告。")
}
override fun onAdShown(event: ShowEvent, error: ShowError?) {
if (error != null) {
Log.e("ChartboostRewarded", "未能对位置${event.ad.location}显示奖励广告:${error.code.name}")
} else {
Log.d("ChartboostRewarded", "奖励广告对于位置${event.ad.location}成功显示。")
}
}
override fun onAdClicked(event: ClickEvent, error: ClickError?) {
val message = if (error == null) {
"位置${event.ad.location}的奖励广告已被点击。"
} else {
"对于位置${event.ad.location},存在奖励广告点击错误:${error.code.name}"
}
Log.d("ChartboostRewarded", message)
}
override fun onAdDismiss(event: DismissEvent) {
Log.d("ChartboostRewarded", "奖励广告对于位置${event.ad.location}关闭。")
showAdButton.isEnabled = false
// 在广告被关闭后缓存下一个广告是不错的做法。
loadRewardedAd()
}
override fun onRewardEarned(event: RewardEvent) {
Log.d("ChartboostRewarded", "用户获得了奖励:${event.reward},原因是观看了位于位置${event.ad.location}的广告。")
// 在此处向用户授予奖励(例如: 10个金币)。
// val currentCoins = sharedPreferences.getInt("user_coins", 0)
// sharedPreferences.edit().putInt("user_coins", currentCoins + event.reward).apply()
// updateUiWithNewCoinBalance(currentCoins + event.reward)
// Log.d("ChartboostRewarded", "用户获得${event.reward}个金币奖励。新余额:${currentCoins + event.reward}")
}
override fun onImpressionRecorded(event: ImpressionEvent) {
Log.d("ChartboostRewarded", "对于位置${event.ad.location},奖励广告曝光已记录。")
}
}, null)
rewardedAd?.cache()
}
private fun showRewardedAd() {
if (rewardedAd != null && rewardedAd!!.isCached()) {
rewardedAd?.show()
} else {
Log.w("ChartboostRewarded", "尝试在$REWARDED_AD_LOCATION显示广告,但是未将其缓存。")
showAdButton.isEnabled = false
// 如果广告不可用则尝试加载广告
loadRewardedAd()
}
}
上述实现的核心是创建一个Rewarded广告对象。这是一个全屏广告,为用户提供reward。在创建Rewarded 对象时,RewardedCallback会处理各种广告生命周期事件:
对于提供重复、基于任务的交互的非流媒体应用而言,奖励广告是一种用户友好的盈利方式。通过集成受支持的SDK并明确地将广告与用户利益联系起来,您可以在不损害体验的情况下盈利。
您正在构建一个利基视频流媒体应用,提供精心策划的内容,如独立电影和音乐视频。您的目标是保持内容免费,同时通过应用内广告产生收入。实现这一目标的典型方法是实现一个受支持的广告SDK,该SDK可以在流媒体应用中提供片前和间隙广告。
对于具有大量内容和流量的企业级应用,亚马逊提供了亚马逊出版商服务 (APS)(仅提供英文版),这是一种程序化的广告解决方案,可以实现亚马逊和第三方广告商的实时竞价。然而,APS只能通过选择性申请流程获得。对于大多数流媒体应用而言,集成兼容的视频广告SDK仍然是最实用、最有效的盈利方式。
流媒体应用特别适合基于广告的盈利,特别是当用户期望免费内容并且会话长度足以容纳多个广告布置时。无论您是在视频之间的自然停顿期间插入广告,还是在播放前的片前时间插入广告,流媒体环境都为高价值的曝光提供了充足的机会,特别是在Fire TV上,视频广告可以全屏显示。
与前面的场景一样,您将首先选择亚马逊支持的广告SDK。然而,您会展示一个插播广告,而不是奖励广告。
在流媒体应用中,您可以在自然断点处放置间隙广告。一种常见的方法是在用户请求播放视频内容时,在片前布置间隙广告。在观看完间隙广告之后,您的应用将向用户显示请求的视频内容。
Chartboost的间隙广告的实现与奖励广告非常相似。和之前的场景一样,从以下操作开始:
然后,您将创建一个Interstitial对象,该对象在InterstitialCallback中实现方法:
interstitialAd = Interstitial("location", object : InterstitialCallback {
override fun onAdDismiss(dismissEvent: DismissEvent) {
// 在广告被关闭时调用
// 将用户返回视频库,不播放请求的视频
}
override fun onAdLoaded(cacheEvent: CacheEvent, cacheError: CacheError) {
// 广告已从Chartboost服务器加载并缓存
// 如果没有CacheError,则广告已准备好显示
}
override fun onAdRequestedToShow(showEvent: ShowEvent) {
// 在展示广告之前调用
}
override fun onAdShown(showEvent: ShowEvent, showError: ShowError?) {
// 在广告已展示或曝光已记录后调用
// 继续播放用户请求的视频
}
override fun onAdClicked(clickEvent: ClickEvent, clickError: ClickError?)
{
// 在广告被点击后调用
// 如果您想在发生这种情况时进行捕获(记录、通知),则使用此项
}
override fun onImpressionRecorded(impressionEvent: ImpressionEvent) {
// 在广告记录了曝光后调用
// 如果您想在发生这种情况时进行捕获(记录、通知),则使用此项
}
}, null)
要缓存间隙,可调用:
interstitialAd.cache()
然后,当您准备显示广告时(在用户请求观看视频之后,但在视频开始流式传输之前),可调用:
if (interstitialAd.isCached()) {
interstitialAd.show()
}
流媒体应用中的广告盈利可以有非常好的效果,尤其是当广告高度相关、位置恰当且无干扰时。无论您是使用受支持的广告SDK还是APS,妥善的集成都能确保在盈利和用户体验之间取得平衡。
一旦您实施了盈利策略,下一步就是了解它的表现,以及哪里需要改进。亚马逊的盈利报表可作为不错的起点,其控制面板涵盖了收入趋势、活跃订阅、保留率和流失率。如果您还没有探索过它们,我们建议您阅读这篇文章,其中介绍了盈利报表并进行了全面概述。
盈利报表只是所涉范围更广的应用统计信息报表中的一种报表。在日常见解方面,这些报表可为您提供有关用户如何与您的应用互动的详细数据。这些报表划分为3个关键区域:
这些信息可帮助您了解用户如何在Fire TV上发现和安装您的应用。用户获取报表显示最大流量来源,包括类别页面、搜索结果和亚马逊策划的布置,如Recommended for You(为您推荐)。
您将看到哪些关键字促成的安装最多,您的应用在搜索结果中出现的频率,以及产生点击或安装的曝光的百分比。这些数据可帮助您优化应用商店产品信息、标题和元数据,以提高可见性和转化率。
跟踪用户在安装后与您应用的交互情况。参与报表 显示每日和每月活跃用户数量、总会话数、平均会话长度和粘性(DAU/MAU比率)等指标。这些见解有助于您了解使用模式并确定高保留率细分市场。您还可以按应用版本细分参与,使您能够衡量功能更改或错误修复对用户活动的影响。
要了解订阅IAP商品的盈利趋势,请查看盈利报表。其中包括“订阅概览”、“保留率”和“取消报表”,这些报告可帮助您跟踪订阅者行为,例如开始、维持或取消订阅的用户有多少,以及对平均持续时间和取消原因的洞察。
对于一次性购买(如消费品或权利)和基于广告的模型,您需要依赖其他应用统计信息报表来获取汇总的IAP事件数据。特别是对于广告收入,可使用您使用的广告SDK提供者的控制面板来跟踪曝光数、填充率和eCPM等关键指标。综合利用这些工具可让您了解如何优化盈利策略,并通过数据驱动的更新来响应用户行为。
通过结合利用上述工具,应用统计信息报表会提供非常有效的有关应用盈利的报告和分析。利用它们来优化您的盈利时机,测试功能布置,并就下一步优化什么做出更明智的决定。
无论您是在构建流媒体应用还是基于任务的实用工具,您的盈利策略应当与用户与内容的实际交互情况相符。订阅、消费品、奖励广告和程序化视频都有自己的作用 - 关键在于根据实际的环境选择正确的工具。
这些SDK、API和开发者工具让您能够灵活地在所有应用类型和设备上实现盈利。通过正确的实现和对性能数据的密切关注,可以构建出一个为用户带来价值的应用程序,同时为您的业务创造重要的收入。