Android Studio 中 Android 应用的 Google Play 许可

Ayx*_*xan 3 android licensing android-lvl kotlin android-studio

我正在尝试为 Android studio 中的一个用 Kotlin 编写的应用程序设置 Google Play 许可。我的目标是避免用户在不通过商店购买我的应用程序的情况下共享 APK 文件。

我尝试过的:

  • 我尝试按照他们的文档进行操作。这不是很有用。它跳过了许多细节,而且它并不是真正的教程。我无法使用它。

  • 我看过这个问题,它确实有一个又长又详细的类似教程的答案。但这个答案似乎早已过时了。它会导致大量警告并以“意图必须明确”异常终止。

我的问题总结是:

如何通过 Google 设置许可证检查,以便未通过商店购买该应用程序的人无法安装它。尽管我无法找到任何正确的答案,但这似乎是一件很常见的事情。

Ayx*_*xan 10

以下是我在 2020 年如何让它发挥作用:

  1. 打开 Android Studio。

  1. 单击“工具”->“SDK 管理器”

在此输入图像描述


  1. 切换到SDK工具选项卡

在此输入图像描述


  1. 确保已安装Google Play 许可库。如果尚未安装,请单击复选标记,然后单击Apply

在此输入图像描述


  1. 在该屏幕中,您可以看到Android SDK Location。复制该路径:

在此输入图像描述


  1. 单击文件 -> 新建 -> 导入模块...

在此输入图像描述


  1. 粘贴您复制的路径,然后单击文本输入行右侧的小文件夹图标:

在此输入图像描述


  1. 单击Android\Sdk\extras\google\market_licensing\library并单击OK

在此输入图像描述


  1. 点击Next

在此输入图像描述


  1. 选中所有内容并单击Finish

在此输入图像描述


  1. library现在您的项目中应该有一个文件夹:

在此输入图像描述


  1. 右键单击app并单击打开模块设置

在此输入图像描述


  1. 单击依赖项

在此输入图像描述


  1. 单击加号按钮并选择3 Module Dependency

在此输入图像描述


  1. 检查library并点击OK

在此输入图像描述


  1. 再次点击OK并等待同步。

  1. 如果出现错误

minSdk 版本不应在 android 清单文件中声明。您可以将版本从清单移动到 build.gradle 文件中的defaultConfig。

转到库 > 清单 > AndroidManifest.xml并删除该行<uses-sdk android:minSdkVersion="3" android:targetSdkVersion="15" />


  1. 转到Gradle 脚本 > build.gradle(模块:库)

在此输入图像描述


  1. 更改minSdkVersion为 4,并根据需要更改compileSdkVersion和,然后buildToolsVersion单击:targetSdkVersionSync Now

在此输入图像描述


  1. 现在库已经准备好了,我们需要实际实施许可证检查。去MainActivity.kt

  1. 您需要找到您的 Base 64 公钥并生成盐,如答案所示。我将引用该答案的必要部分,但将代码翻译为 Kotlin:

1.1 您的 Base64 唯一应用程序密钥

如何获得:

A。转到您的开发者控制台。关联

b. 如果您尚未为您的应用创建申请草案,请立即创建。

C。创建草稿后,最好将草稿上传 .apk为 Alpha 版或 Beta 版。让它不发布。

d. 点击Services & APIs

e. 向下滚动并找到YOUR LICENSE KEY FOR THIS APPLICATION

F。将密钥复制到您的应用程序中,如下所示:

private const val BASE64_PUBLIC_KEY = "YOUR LICENSE KEY FOR THIS APPLICATION";
Run Code Online (Sandbox Code Playgroud)

确保没有空格。

1.2 盐

A。什么是盐?

盐是随机数据是散列密码时的附加输入。它们用于防御字典攻击彩虹表攻击。

b. 我怎样才能得到一个?

是生成随机盐的好链接。应该正好有 20 个随机整数,因此输入20要生成的随机字符串的数量,每个字符串应该是2字符长(用于本示例,但不一定如此)。检查数字,并检查是否允许相同的字符串。它们也可以是负数。尝试删除任何冗余,例如00 -> 0,为了一致性。

C。我该把盐放在哪里?

声明变量时,只需放入此代码即可,除非使用随机盐。

private val SALT = byteArrayOf(YOUR RANDOM SALT COMMA SEPARATED 20 INTEGERS)
Run Code Online (Sandbox Code Playgroud)

  1. 步骤 21 中的变量应添加到您的主要活动类中。现在,您应该向您的主要活动添加一些代码。大致看起来应该是这样的(注意// TODO评论):
import android.os.Bundle
import android.provider.Settings
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.android.vending.licensing.*
import kotlin.system.exitProcess

class MainActivity : AppCompatActivity()
{
    companion object
    {
        private const val BASE64_PUBLIC_KEY = "YOUR LICENSE KEY FOR THIS APPLICATION" // TODO replace with your own key

        private val SALT = byteArrayOf(YOUR RANDOM SALT COMMA SEPARATED 20 INTEGERS) // TODO replace with your own salt
        
    }
    
    private val deviceId: String by lazy {
        Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
    }
    private lateinit var licenseCheckerCallback: LicenseCheckerCallback
    private lateinit var checker: LicenseChecker
    
    private fun doCheck()
    {
        checker.checkAccess(licenseCheckerCallback)
    }

    override fun onDestroy()
    {
        super.onDestroy()
        checker.onDestroy()
    }



    override fun onCreate(savedInstanceState: Bundle?)
    {
        super.onCreate(savedInstanceState)

        // Construct the LicenseCheckerCallback. The library calls this when done.
        licenseCheckerCallback = MyLicenseCheckerCallback()

        // Construct the LicenseChecker with a Policy.
        checker = LicenseChecker(
            this,
            ServerManagedPolicy(this, AESObfuscator(SALT, packageName, deviceId)),
            BASE64_PUBLIC_KEY // Your public licensing key.
        )

        doCheck()

        setContentView(R.layout.activity_main) // TODO Replace with your own layout
    }

    private fun displayResult(result: String)
    {
         // TODO you can change this how the info is displayed
        Toast.makeText(this, result, Toast.LENGTH_SHORT).show()
    }

    private inner class MyLicenseCheckerCallback : LicenseCheckerCallback
    {
        override fun allow(reason: Int)
        {
            if (isFinishing)
            {
                // Don't update UI if Activity is finishing.
                return
            }
            // Should allow user access.
        }

        override fun applicationError(errorCode: Int)
        {
             // TODO handle the error your own way. Calling `dontAllow` is common.
            dontAllow(Policy.NOT_LICENSED)
        }

        override fun dontAllow(reason: Int)
        {
            if (isFinishing)
            {
                // Don't update UI if Activity is finishing.
                return
            }
            

            if (reason == Policy.RETRY)
            {
                // If the reason received from the policy is RETRY, it was probably
                // due to a loss of connection with the service, so we should give the
                // user a chance to retry. So show a dialog to retry.

                // TODO handle Policy.RETRY
            }
            else
            {
                // Otherwise, the user isn't licensed to use this app.
                // Your response should always inform the user that the application
                // isn't licensed, but your behavior at that point can vary. You might
                // provide the user a limited access version of your app or you can
                // take them to Google Play to purchase the app.

                // TODO implement goto market
            }
            displayResult("Not Licensed")
            
            // TODO you may not abort if you have some other way to handle the fail case
            abort()
        }
    }

    private fun abort()
    {
        finishAffinity()
        exitProcess(0) 
    }
}
Run Code Online (Sandbox Code Playgroud)
  1. 将这些权限添加到您的清单文件中:
<uses-permission android:name="android.permission.INTERNET"/>  
<uses-permission android:name="com.android.vending.CHECK_LICENSE"/>
Run Code Online (Sandbox Code Playgroud)
  1. 如果您收到异常并显示类似以下内容的消息:
Service Intent must be explicit: Intent { act=com.android.vending.licensing.ILicensingService }
Run Code Online (Sandbox Code Playgroud)

应用此答案中的修复。


  1. 这应该就是全部了。请参阅我之前引用的答案以获取更多信息。我希望这可以节省其他人一些时间。