Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

✅  Google Play License Check | Protect your game from piracy and hacking

Discussion in 'Assets and Asset Store' started by KyryloKuzyk, Jul 20, 2022.

  1. KyryloKuzyk

    KyryloKuzyk

    Joined:
    Nov 4, 2013
    Posts:
    1,149
    Available on Asset Store
    Documentation
    FAQ
    Support
    Hi developers,

    I want to introduce my new plugin: Google Play License Check. This plugin will help you to protect your game by integrating with the Google Play App Licensing service in a few lines of code.

    420x280.png

    To show how easy it is to integrate the plugin into your existing project, let's consider the following code:
    Code (CSharp):
    1. GooglePlayLicense.Check(license => {
    2.     if (license.status == LicenseStatus.NOT_LICENSED) {
    3.         Debug.Log("YOU ARE A PIRATE, SHAME ON YOU!");
    4.     }
    5. });
    Yes, it's that simple! After performing the license check, the plugin will cache the response and store it in the PlayerPrefs. To access the cached license:
    Code (CSharp):
    1. var cachedLicense = GooglePlayLicense.cachedLicense;
    2. if (cachedLicense != null) {
    3.     Debug.Log($"License is valid: {cachedLicense.isLicenseValid}. Grace period: {cachedLicense.gracePeriodTimestamp}.");
    4. }
    To add extra protection to your app, you can provide your custom secure storage instead of using PlayerPrefs:
    Code (CSharp):
    1. GooglePlayLicense.SetPersistentStorageImplementation(MyAwesomeSecureStorage.SaveString, MyAwesomeSecureStorage.LoadString);
    That's it!
    Your game is now protected from pirates and hacking.

    As a bonus for Google Play Pass developers, the plugin is compatible with paid Google Play Pass games. Integrating with the Play Pass service may be a cumbersome process for Unity developers, but not anymore! Spend time developing your awesome game instead of fighting with unstructured third-party code.

    Documentation
    FAQ
    Support

    Available on Asset Store
     
    Last edited: Apr 21, 2023
  2. KyryloKuzyk

    KyryloKuzyk

    Joined:
    Nov 4, 2013
    Posts:
    1,149
    Version 1.2.2 Update

    The new 1.2.2 update brings Unity 2018.4.36 support and is already available on Asset Store. Just because you use an old Unity version doesn't mean you have to compromise on protecting your intellectual property.

    'Google Play License Check' plugin installs as Unity Package Manager (UPM) package to keep your projects clean. While Unity 2018 does support UPM packages, it doesn't have a nice GUI support for them, so importing Samples via Package Manager is not possible. I'll post the example scripts here for those who use Unity 2018 and for all potential customers who'd like to see the examples of plugin's usage.

    Code (CSharp):
    1. #if UNITY_ANDROID
    2. using GooglePlay;
    3. #endif
    4. using UnityEngine;
    5.  
    6.  
    7. public class BasicExample : MonoBehaviour {
    8.     void Awake() {
    9.         #if UNITY_ANDROID
    10.         log("Checking license...");
    11.         GooglePlayLicense.Check(license => {
    12.             log($"GooglePlayLicense.Check() finished with result:\n{license}");
    13.             if (license.status == LicenseStatus.LICENSED) {
    14.                 log($"The app is licensed, license is valid until {license.licenseValidityTimestamp}. Grace period: {license.gracePeriodTimestamp}.");
    15.                 // TODO: unlock the premium content.
    16.             }
    17.          
    18.             if (license.status == LicenseStatus.NOT_LICENSED) {
    19.                 var licensingUrl = license.licensingUrl;
    20.                 if (licensingUrl != null) {
    21.                     log($"The app is NOT licensed. Showing the paywall by redirecting the user to [{licensingUrl}]...");
    22.                     GooglePlayLicense.OpenLicensingUrl(licensingUrl);  
    23.                 } else {
    24.                     log("The app is sideloaded or the user is not signed in to Google account. Showing app details page on Google Play");
    25.                     Application.OpenURL($"market://details?id={Application.identifier}");
    26.                 }
    27.              
    28.                 // TODO: decide what to do if the app is not licensed. Lock the premium content, display banner, or simply call Application.Quit().
    29.             }
    30.         });
    31.         #endif
    32.     }
    33.  
    34.  
    35.     string debugString = "";
    36.  
    37.     void log(string message) {
    38.         Debug.Log(message);
    39.         debugString += $"{message}\n\n";
    40.     }
    41.  
    42.     void OnGUI() {
    43.         #if IMGUI_INSTALLED || UNITY_2018
    44.         const int margin = 30;
    45.         var position = new Rect(margin, margin, Screen.width - margin * 2, Screen.height - margin * 2);
    46.         var style = new GUIStyle {
    47.             fontSize = Screen.width / 70,
    48.             normal = new GUIStyleState {textColor = Color.white},
    49.             alignment = TextAnchor.UpperLeft
    50.         };
    51.  
    52.         GUI.Label(position, debugString, style);
    53.         #endif
    54.     }
    55. }
    56.  
    Code (CSharp):
    1. #if UNITY_ANDROID
    2. using GooglePlay;
    3. #endif
    4. using UnityEngine;
    5.  
    6.  
    7. public class AdvancedExample : MonoBehaviour {
    8.     void Awake() {
    9.         #if UNITY_ANDROID
    10.         // Provide a secure way to store cached license response instead of saving to PlayerPrefs.
    11.         GooglePlayLicense.SetPersistentStorageImplementation(MyAwesomeSecureStorage.SaveString, MyAwesomeSecureStorage.LoadString);
    12.        
    13.         var cachedLicense = GooglePlayLicense.cachedLicense;
    14.         if (cachedLicense == null) {
    15.             print("The app has never received the Google Play license response before.");
    16.         } else {
    17.             print("The app has received Google Play license response before. The cache is:\n" +
    18.                   $"Status: [{cachedLicense.status}], timestamp: [{cachedLicense.timestamp}]\n" +
    19.                   $"LicenseValidityTimestamp: [{cachedLicense.licenseValidityTimestamp}], gracePeriodTimestamp: [{cachedLicense.gracePeriodTimestamp}]");
    20.         }
    21.        
    22.         const string publicRSAKeyBase64 = "PASTE_YOUR_BASE_64_ENCODED_RSA_PUBLIC_KEY_HERE";
    23.         var config = new GooglePlayLicenseConfig(publicRSAKeyBase64) {
    24.             waitForInternetConnection = true,
    25.             maxRetries = 5,
    26.             initialRetryPeriod = 2,
    27.             backoffExponent = 2,
    28.             enableVerboseLogging = true
    29.         };
    30.         GooglePlayLicense.Check(config, license => {
    31.             print($"GooglePlayLicense.Check() finished with result:\n{license}");
    32.         });
    33.         #endif
    34.     }
    35.  
    36.     static class MyAwesomeSecureStorage {
    37.         const string notImplementedError = "TODO: implement your custom secure storage for cached license response.";
    38.         const string key = "GooglePlayCachedLicenseResponse";
    39.        
    40.         public static void SaveString(string str) {
    41.             Debug.LogError(notImplementedError);
    42.             PlayerPrefs.SetString(key, str);
    43.             PlayerPrefs.Save();
    44.         }
    45.  
    46.         public static string LoadString() {
    47.             Debug.LogError(notImplementedError);
    48.             return PlayerPrefs.GetString(key, "");
    49.         }
    50.     }
    51. }
    52.  

    Happy coding!