【问题标题】:Google Play Licencing for an Android app in Android StudioAndroid Studio 中 Android 应用的 Google Play 许可
【发布时间】:2021-01-22 12:37:22
【问题描述】:

我正在尝试为 Android Studio 中的应用设置 Google Play 许可,以使用 Kotlin 编写的应用。我的目标是避免用户在未通过商店购买我的应用的情况下共享 APK 文件。

我尝试过的:

  • 我尝试过关注他们的documentation。它不是很有用。它跳过了许多细节,并不是真正的教程。我无法使用它。

  • 我看过this 问题,它确实有一个冗长而详细的类似教程的答案。但答案似乎早已过时。它会导致大量警告并以异常“Intent must be explicit”终止。

我的问题总结是:

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

【问题讨论】:

    标签: android android-studio kotlin licensing android-lvl


    【解决方案1】:

    以下是我在 2020 年的工作方式:

    1. 打开 Android Studio。

    1. 点击工具 -> SDK 管理器


    1. 切换到 SDK 工具 标签


    1. 确保已安装 Google Play 许可库。如果未安装,请单击复选标记并单击应用


    1. 在该屏幕上方,您可以看到 Android SDK 位置。复制该路径:


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


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


    1. 点击Android\Sdk\extras\google\market_licensing\library,然后点击确定


    1. 点击下一步


    1. 选中所有内容并单击完成


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


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


    1. 点击依赖项


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


    1. 勾选library并点击OK


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

    1. 如果出现错误

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

    转到 library > manifests > AndroidManifest.xml 并删除 <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="15" /> 行。


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


    1. minSdkVersion更改为4,并根据需要更改compileSdkVersionbuildToolsVersiontargetSdkVersion,然后单击Sync Now


    1. 现在库已准备就绪,我们需要实际实施许可证检查。转至MainActivity.kt

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

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

    如何获得:

    一个。转到您的开发者控制台。 Link.

    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";
    

    确保没有空格。

    1.2 一种盐

    一个。什么是盐?

    salt 是随机数据,在散列 a 时作为附加输入 密码。它们用于防御dictionary attacksrainbow table 攻击。

    b.如何获得?

    This 是生成随机盐的好链接。 应该有 20 个随机整数,所以将20 放入随机字符串的数量为 生成,每个字符串应为2 个字符长(用于此 例如,它不一定是)。检查数字,然后检查 允许使用相同的字符串。它们也可以是负数。尝试 删除任何冗余,例如00 -> 0,为了保持一致。

    c。我在哪里放盐?

    当声明变量时,只需将这段代码放入,除了你的 随机盐。

    private val SALT = byteArrayOf(YOUR RANDOM SALT COMMA SEPARATED 20 INTEGERS)
    

    1. 第 21 步中的变量应该添加到您的主要活动类中。现在,您应该在主要活动中添加一些代码。大概是这样的(注意// TODOcmets):
    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) 
        }
    }
    

    1. 将这些权限添加到您的清单文件中:
    <uses-permission android:name="android.permission.INTERNET"/>  
    <uses-permission android:name="com.android.vending.CHECK_LICENSE"/>
    

    1. 如果您收到类似以下消息的异常:
    Service Intent must be explicit: Intent { act=com.android.vending.licensing.ILicensingService }
    

    this 答案中应用修复。


    1. 应该就是这样。有关更多信息,请参阅我之前引用的 answer。我希望这可以节省其他人一些时间。

    【讨论】:

    • 干得好。非常好的手册。我可以只使用库而不是模块吗?你必须对此进行测试。好吗?
    • 只有图书馆是什么意思?
    • @Style-7 import module 部分是 Google 文档导入它的方式。您有其他建议吗?
    • 添加为库。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-11
    • 2012-10-28
    • 1970-01-01
    • 2014-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多