Google Play Licencing for an Android app in Android Studio

别来无恙 提交于 2020-07-23 06:43:17

问题


I am trying to set up Google Play Licencing for an app in Android studio for an app written in Kotlin. My goal is to avoid users sharing APK files without purchasing my app through the store.

What I've tried:

  • I've tried following through their documentation. It's not very useful. It skips over many details and it's not really a tutorial. I couldn't use it.

  • I've seen this question, which does have a long and detailed tutorial-like answer. But the answer seems long-outdated. It causes lots of warnings and terminates with an exception "Intent must be explicit".

My question in summary is:

How can I set up license checking through Google so people who haven't purchased the app through the store can't install it. This seems to be a very common thing to do even though I couldn't manage to find much of any proper answer around.


回答1:


Here's how I got it working in 2020:

  1. Open Android Studio.

  1. Click Tools -> SDK Manager


  1. Switch to the SDK Tools tab


  1. Make sure Google Play Licensing Library is installed. If it's not installed, click the checkmark and click Apply.


  1. Up in that screen you can see Android SDK Location. Copy that path:


  1. Click File -> New -> Import Module...:


  1. Paste the path you copied and click the small folder icon on the right of the text-input line:


  1. Click Android\Sdk\extras\google\market_licensing\library and click OK:


  1. Click Next:


  1. Leave everything checked and click Finish:


  1. Now you should have a library folder in your project:


  1. Right click on app and click Open Module Settings:


  1. Click Dependencies:


  1. Click the plus button and choose 3 Module Dependency:


  1. Check library and click OK:


  1. Click OK again and wait for it to sync.

  1. If you get an error

The minSdk version should not be declared in the android manifest file. You can move the version from the manifest to the defaultConfig in the build.gradle file.

Go to library > manifests > AndroidManifest.xml and remove the line <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="15" />.


  1. Go to Gradle Scripts > build.gradle (Module: library):


  1. Change minSdkVersion to 4 and also change compileSdkVersion, buildToolsVersion and targetSdkVersion as necessary, then click Sync Now:


  1. Now that the library is ready, we need the actual implementation of the license checking. Go to MainActivity.kt.

  1. You need to find your Base 64 public key and also generate a salt as shown in this answer. I am going to quote the necessary part of that answer but translate the code to Kotlin:

1.1 Your Base64 unique application key

How to get it:

a. Go to your developer console. Link.

b. If you haven't already created an application draft for your app, do it now.

c. Once you have created the draft, it is a good idea to upload your .apk as Alpha or Beta. Leave it unpublished.

d. Click Services & APIs

e. Scroll down and find YOUR LICENSE KEY FOR THIS APPLICATION

f. Copy the key into your app like this:

private const val BASE64_PUBLIC_KEY = "YOUR LICENSE KEY FOR THIS APPLICATION";

Make sure that there are no spaces.

1.2 A salt

a. What is a salt?

A salt is random data that is additional input when hashing a password. They are used to defend against dictionary attacks and rainbow table attacks.

b. How do I get one?

This is a good link to generate a random salt. There should be exactly 20 random integers, so put 20 in for the amount of random strings to generate, each string should be 2 characters long (used for this example, it doesn't have to be). Check numeric digits, and check Identical strings are allowed. They can be negative numbers too. Try to remove any redundancy, e.g. 00 -> 0, for the sake of consistency.

c. Where do I put the salt?

When declaring variables just put this code in, except with your random salt.

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

  1. Variables in step 21 should be added to your main activity class. Now, you should add some code to your main activity. Here's what it should roughly look like (Pay attention to // TODO comments):
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. Add these permissions to your manifest file:
<uses-permission android:name="android.permission.INTERNET"/>  
<uses-permission android:name="com.android.vending.CHECK_LICENSE"/>

  1. If you get an exception with a message similar to:
Service Intent must be explicit: Intent { act=com.android.vending.licensing.ILicensingService }

Apply the fix in this answer.


  1. That should be all. See the answer I quoted previously for more info. I hope this saves others some time.


来源:https://stackoverflow.com/questions/62852617/google-play-licencing-for-an-android-app-in-android-studio

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!