הוספת אימות של רישיון מצד הלקוח לאפליקציה

אזהרה: כשהאפליקציה תבצע את תהליך אימות הרישיון בתאריך בצד הלקוח, קל יותר לתוקפים פוטנציאליים לשנות או להסיר הלוגיקה שמשויכת לתהליך האימות הזה.

לכן, אנחנו ממליצים מאוד ביצוע בצד השרת לבצע אימות של הרישיון.

אחרי שהגדרתם חשבון בעל תוכן דיגיטלי וסביבת פיתוח (מידע נוסף זמין במאמר הגדרה לרישוי), אתם מוכנים להוסיף את אימות הרישיון כדי לאפליקציה שלך באמצעות ספריית אימות הרישיון (LVL).

הוספת אימות רישיון באמצעות LVL כוללת את המשימות הבאות:

  1. הוספת הרשאת רישוי במניפסט של האפליקציה.
  2. הטמעת מדיניות — אתם יכולים לבחור אחת מההטמעות המלאות שמפורטות ב-LVL או ליצור הטמעה משלכם.
  3. הטמעה של ערפול קוד (obfuscator), אם ה-Policy יישמר במטמון של חלק מהרישיונות.
  4. הוספת קוד לבדיקת הרישיון בכרטיסייה הראשית של האפליקציה פעילות.
  5. הטמעת DeviceLimiter (אופציונלי ולא מומלץ עבור את רוב האפליקציות).

הקטעים הבאים מתארים את המשימות האלה. כשתסיימו עם אמורה להיות לכם אפשרות להדר את האפליקציה ניתן להתחיל בבדיקות, כפי שמתואר בהגדרת הבדיקה סביבה.

לסקירה כללית של הקבוצה המלאה של קובצי המקור שכלולה ב-LVL, ראו סיכום של מחלקות LVL וממשקים.

הוספת הרשאת רישוי

כדי להשתמש באפליקציית Google Play לשליחת בדיקת רישיון השרת, האפליקציה שלכם חייבת לבקש את ההרשאה המתאימה, com.android.vending.CHECK_LICENSE אם האפליקציה שלכם לא מצהיר על הרשאת רישיון, אלא מנסה לבצע בדיקת רישיון, LVL גורם חריגת אבטחה.

כדי לבקש הרשאת רישוי באפליקציה, צריך להצהיר על <uses-permission> כצאצא של <manifest>, באופן הבא:

<uses-permission android:name="com.android.vending.CHECK_LICENSE" />

לדוגמה, כך מוצהר על ההרשאה באפליקציה לדוגמה של LVL:

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android" ...">
    <!-- Devices >= 3 have version of Google Play that supports licensing. -->
    <uses-sdk android:minSdkVersion="3" />
    <!-- Required permission to check licensing. -->
    <uses-permission android:name="com.android.vending.CHECK_LICENSE" />
    ...
</manifest>

הערה: בשלב הזה, אי אפשר להצהיר על הרשאת CHECK_LICENSE במניפסט של ספריית הפרויקט LVL, כי כלי ה-SDK לא ימזגו אותו במניפסטים של תרגום מכונה. במקום זאת, צריך להצהיר על ההרשאה עבור כל אחד מהתלויים למניפסט של האפליקציה.

יישום מדיניות

שירות הרישוי של Google Play לא קובע בעצמו אם צריך להעניק למשתמש בעל רישיון מסוים גישה לאפליקציה. במקום זאת, האחריות על ההטמעה של Policy שאתם מספקים באפליקציה שלכם.

המדיניות היא ממשק שהוצהר על ידי ה-LVL ונועד להחזיק הלוגיקה של האפליקציה לאישור או לחסימה של גישת משתמש, על סמך התוצאה של בדיקת רישיון. כדי להשתמש ב-LVL, האפליקציה חייבת לספק של Policy.

בממשק Policy מוצהרות שתי שיטות, allowAccess() ו processServerResponse(), אותן מתבצעת על ידי LicenseChecker במהלך עיבוד תגובה משרת הרישיונות. כמו כן, היא מצהירה טיפוס enum שנקרא LicenseResponse, שמציין את תגובת הרישיון הערך שהועבר בשיחות אל processServerResponse().

  • באמצעות processServerResponse() אפשר לעבד מראש את התשובה הגולמית שהתקבלו משרת הרישוי, לפני שהחלטתם אם להעניק או לא גישה.

    הטמעה אופיינית תשלוף חלק מהשדות או את כולם מהרישיון ולאחסן את הנתונים באופן מקומי בחנות קבועה, למשל אחסון בנפח SharedPreferences, כדי לוודא שהנתונים נגישים בכל הפעלות של אפליקציות ומחזורי הפעלה של המכשיר. לדוגמה, Policy ישמור את חותמת הזמן של בדיקת הרישיון האחרונה, את מספר הניסיונות החוזרים, תקופת התוקף של הרישיון ומידע דומה אחסון מתמיד, במקום לאפס את הערכים בכל פעם הושק.

    כשמאחסנים נתוני תשובות באופן מקומי, Policy חייב לוודא שהנתונים ערפול קוד (obfuscation) (ראו הטמעת ערפול קוד (obfuscator), למטה).

  • allowAccess() קובע אם להעניק למשתמש גישה אל על סמך נתוני תגובה זמינים לרישיון (מ שרת רישוי או מהמטמון) או מידע אחר שהוא ספציפי לאפליקציה. עבור לדוגמה, ההטמעה של allowAccess() עשויה לקחת קריטריונים נוספים בחשבון, כגון שימוש או נתונים אחרים שאוחזרו שרת עורפי. בכל המקרים, הטמעה של allowAccess() צריך להחזיר true רק אם המשתמש מורשה להשתמש כפי שנקבע על ידי שרת הרישוי, או אם קיים סטטוס זמני בעיה ברשת או במערכת שמונעת את השלמת בדיקת הרישיון. לחשבון במקרים כאלה, ההטמעה יכולה לשמור על מספר התשובות של הניסיונות החוזרים לאפשר גישה באופן זמני עד להשלמת בדיקת הרישיון הבאה.

כדי לפשט את התהליך של הוספת רישוי לאפליקציה להמחשה של עיצוב Policy, ה-LVL כולל שתי הטמעות מלאות של Policy שניתן להשתמש בהן ללא שינוי או בהתאם לצרכים שלכם:

  • ServerManagedPolicy, מדיניות גמישה של Policy שמשתמש בהגדרות שסופקו על ידי השרת ובתגובות שנשמרו במטמון כדי לנהל את הגישה תנאי רשת שונים,
  • StrictPolicy, שלא שומר תגובות במטמון ומאפשר גישה רק אם השרת מחזיר רישיון תשובה.

ברוב האפליקציות, השימוש ב-ServerManagedPolicy הוא מאוד מומלץ. ServerManagedPolicy הוא ה-LVL שמוגדר כברירת המחדל והוא משולב עם של אפליקציית ה-LVL לדוגמה.

הנחיות למדיניות מותאמת אישית

כחלק מהטמעת הרישיון, אפשר להשתמש באחת מכללי המדיניות המלאים המסופקים ב-LVL (ServerManagedPolicy או StrictPolicy) או תוכלו ליצור מדיניות מותאמת אישית. לכל סוג של מדיניות מותאמת אישית יש מספר עיצובים חשובים שחשוב להבין וליישם אותן.

שרת הרישוי מחיל מגבלות בקשות כלליות כדי להגן מפני שימוש יתר משאבים שעלולים להוביל להתקפת מניעת שירות (DoS). כשאפליקציה חורגת מגבלת הבקשות, שרת הרישוי מחזיר תגובה 503, שהועברה לאפליקציה כשגיאת שרת כללית. המשמעות היא שלא תהיה זמינה למשתמש עד שהמגבלה תתאפס, עלולות להשפיע על המשתמש לזמן בלתי מוגבל.

אם בכוונתך לעצב מדיניות מותאמת אישית, מומלץ: Policy:

  1. שומר במטמון (ומערפל בצורה תקינה) את התגובה האחרונה המוצלחת של הרישיון באחסון מקומי מתמיד.
  2. מחזירה את התגובה שנשמרה במטמון עבור כל בדיקות הרישיונות, כל עוד התגובה שנשמרה במטמון תקפה ולא לשלוח בקשה לשרת הרישוי. הגדרת תוקף התגובה בהתאם ל-VT שסופק על ידי השרת מומלץ מאוד. למידע נוסף, ראו תוספות לתגובת שרת אפשר לקבל מידע נוסף.
  3. משתמש בתקופת השהיה מעריכית לפני ניסיון חוזר (exponential backoff), אם מתבצע ניסיון חוזר של בקשות כלשהן התוצאה שגיאות. לתשומת ליבך: לקוח Google Play מנסה לבצע ניסיון חוזר באופן אוטומטי לכן ברוב המקרים אין צורך ב-Policy כדי לנסות שוב.
  4. מציין 'תקופת חסד' שמאפשרת למשתמש לגשת לזמן מוגבל או למספר מוגבל של שימושים, בזמן שמתבצעת בדיקת רישיון בוצע ניסיון נוסף. תקופת החסד מועילה למשתמש מפני שהיא מאפשרת גישה עד בדיקת רישיונות תושלם בהצלחה, והיא תועיל לך על ידי הצבה הגבלה קשיחה על גישה לאפליקציה כאשר אין תגובה תקפה לרישיון זמינים.

חשוב מאוד לתכנן את הPolicy בהתאם להנחיות שלמעלה, כי זה מבטיח את החוויה הטובה ביותר האפשרית עבור המשתמשים, וגם שליטה יעילה באפליקציה שלכם גם במצב של שגיאות.

לתשומת ליבך, כל Policy יכול להשתמש בהגדרות שסופקו על ידי שרת הרישוי כדי עוזרות לנהל את התוקף והשמירה במטמון, לבצע ניסיון חוזר של תקופת חסד ועוד. חילוץ של ההגדרות שסופקו על ידי השרת הן פשוטות, והשימוש בהן מאוד מומלץ. לדוגמה, אפשר לעיין בהטמעה של ServerManagedPolicy לחלץ את התוספות ולהשתמש בהן. לרשימה של הגדרות שרת ומידע על כיצד להשתמש בהן, ראו תגובה מהשרת תוספות.

מדיניות מנוהלת של Server

LVL כולל הטמעה מלאה ומומלצת של Policy ממשק שנקרא ServerManagedPolicy. ההטמעה משולבת עם מחלקות LVL ומשמשות כ-Policy ברירת המחדל בספרייה.

ServermanagedPolicy מספק את כל הטיפול ברישיונות ובניסיונות חוזרים תשובות מדויקות. היא שומרת במטמון את כל נתוני התגובות באופן מקומי SharedPreferences, לבצע ערפול קוד (obfuscation) שלו באמצעות יישום Obfuscator של האפליקציה. כך אפשר לוודא שתגובת הרישיון הנתונים מאובטחים ונשמרים בכל מחזורי ההפעלה של המכשיר. מדיניות מנוהלת של Server מספקת הטמעות קונקרטיות של שיטות הממשק processServerResponse(), allowAccess() וגם הדוח כולל קבוצה של שיטות וסוגים תומכים לניהול רישיונות תשובות מדויקות.

חשוב לציין שתכונה חשובה של ServerManagedPolicy היא השימוש בו להגדרות שסופקו על ידי השרת כבסיס לניהול רישוי בכל תקופת ההחזר הכספי של האפליקציה ובאמצעות תנאי רשת ושגיאות שונים. כשאפליקציה יוצרת קשר עם שרת Google Play לצורך בדיקת רישיון, השרת מצרף מספר הגדרות בתור צמדי מפתח-ערך בשדה התוספות של נתונים סוגי התגובה לרישיונות. לדוגמה, השרת מספק ערכים מומלצים עבור תוקף הרישיון של הבקשה, תקופת החסד של ניסיון חוזר, ותקופת החסד המקסימלית מספר ניסיונות חוזרים, בין היתר. ServermanagedPolicy מחלץ את הערכים מה- של הרישיון בשיטה processServerResponse() ובבדיקות בשיטה ה-allowAccess() שלה. לרשימה של ההגדרות שבהן נעשה שימוש על ידי ServerManagedPolicy, כאן אפשר לעיין בתגובת השרת תוספות.

מטעמי נוחות, הביצועים הטובים ביותר והיתרון של השימוש בהגדרות הרישיון משרת Google Play, באמצעות ServerManagedPolicy בתור מומלץ מאוד להוסיף רישיון ל-Policy.

אם יש לך חשש לגבי האבטחה של נתוני תגובה לרישיון, מאוחסנים באופן מקומי ב-SharedPreferences, אפשר להשתמש בערפול קוד (obfuscation) חזק יותר או לתכנן Policy מחמיר יותר שלא מאחסן נתוני רישיונות. LVL כולל דוגמה ל-Policy כזה - למידע נוסף, ראו StrictPolicy.

כדי להשתמש ב-ServerManagedPolicy, פשוט ייבא אותו לפעילות שלך, צור ונעביר הפניה למכונה בזמן הבנייה LicenseChecker לפרטים נוספים, אפשר לעיין ב-Instantiate LicenseChecker LicenseCheckerCallback לקבלת מידע נוסף.

מדיניות מחמירה

LVL כולל הטמעה מלאה חלופית של הממשק של Policy שנקרא StrictPolicy. ההטמעה של StrictPolicy מספקת לפי המדיניות ServerManagedPolicy, שהיא לא מאפשרת למשתמש לגשת של האפליקציה, אלא אם התקבלה תגובת רישיון מהשרת זמן גישה שמציין שהמשתמש מורשה.

התכונה העיקרית של StrictPolicy היא שהיא לא מאחסנת אף לקבל רישיון באופן מקומי, בחנות קבועה. מכיוון שלא נשמרים נתונים, לא מתבצע מעקב אחרי בקשות חוזרות ולא ניתן להשתמש בתגובות שנשמרו במטמון את בדיקות הרישיון. Policy מאפשרת גישה רק אם:

  • תגובת הרישיון מתקבלת משרת הרישוי.
  • תגובת הרישיון מציינת שהמשתמש מורשה לגשת אל תרגום מכונה.

השימוש ב-StrictPolicy מתאים אם החששות העיקריים שלכם הם להבטיח בכל המקרים האפשריים, אף משתמש לא יוכל לגשת לאפליקציה אלא אם מאושר שהמשתמש בעל רישיון בזמן השימוש. בנוסף, המדיניות מספקת אבטחה קצת יותר גבוהה מזו של ServerManagedPolicy – כי אין נתונים במטמון באופן מקומי, אין דרך שמשתמש זדוני יוכל לעשות שינויים את הנתונים שנשמרו במטמון ולקבל גישה לאפליקציה.

במקביל, Policy מציג אתגר למשתמשים רגילים, מכיוון שהוא פירושו שהם לא יוכלו לגשת לאפליקציה כשאין רשת יש חיבור לרשת סלולרית או לרשת Wi-Fi. תופעת לוואי נוספת היא ישלח לשרת בקשות נוספות לבדיקת רישיונות, מכיוון שהשתמשנו ב- תגובה שנשמרה במטמון אינה אפשרית.

באופן כללי, המדיניות הזו מייצגת איזון של מידה מסוימת של נוחות המשתמש לאבטחה מוחלטת ושליטה בגישה. שוקלים את הפשרה בקפידה לפני שמשתמשים בPolicy הזה.

כדי להשתמש ב-StrictPolicy, צריך לייבא אותו לפעילות, ליצור מכונה, ולהעביר אליו הפניה כאשר בונים את LicenseChecker. צפייה Instantiate LicenseChecker ו- LicenseCheckerCallback אפשר לקבל מידע נוסף.

הטמעה אופיינית של Policy צריכה לשמור את נתוני התגובה לרישיון של אפליקציה לאחסון קבוע, כדי שאפשר יהיה לגשת אליה דרך הפעלות של אפליקציות ומחזורי הפעלה של המכשיר. לדוגמה, Policy לשמור את חותמת הזמן של בדיקת הרישיון האחרונה שבוצעה, את מספר הניסיונות החוזרים תקופת תוקף הרישיון ומידע דומה בחנות קבועה, במקום לאפס את הערכים בכל פעם שהאפליקציה מופעלת. ברירת המחדל של Policy כלולה ב-LVL, ServerManagedPolicy, או מאחסן את התגובה במכונה של SharedPreferences, כדי לוודא קבועים.

כי Policy ישתמש בנתוני תגובה מאוחסנים של הרישיון כדי לקבוע אם כדי לאפשר או למנוע גישה לאפליקציה, חייב לוודא הנתונים המאוחסנים מאובטחים ולא ניתן לעשות בהם שימוש חוזר או לשנות אותם על ידי משתמש ברמה הבסיסית (root) במכשיר. באופן ספציפי, Policy תמיד צריך לערפל את הנתונים לפני האחסון באמצעות מפתח ייחודי לאפליקציה ולמכשיר. ערפול קוד (obfuscation) באמצעות מפתח שהוא ספציפי לאפליקציה וספציפי למכשיר הוא קריטי, מכיוון הוא מונע שיתוף של הנתונים המעורפלים בין אפליקציות מכשירים.

ה-LVL מסייע לאפליקציה לאחסן את נתוני התגובות לרישיון בצורה מאובטחת ועקבית. קודם כול, הוא מספק Obfuscator שמאפשר לאפליקציה לספק את האלגוריתם לערפול קוד (obfuscation) עבור הנתונים המאוחסנים. על בסיס זה, ה-LVL מספק את המחלקה המסייעת PreferenceObfuscator, שמטפל ברוב העבודה של הפעלת את הכיתה Obfuscator של האפליקציה, וקריאה וכתיבה של הנתונים המעורפלים מופע אחד (SharedPreferences).

ה-LVL מספק הטמעה מלאה של Obfuscator שנקראת AESObfuscator שמשתמש בהצפנת AES כדי להסתיר נתונים. אפשר להשתמש ב-AESObfuscator באפליקציה ללא שינוי או שלא להתאים אותו לצרכים שלכם. אם משתמשים ב-Policy (כמו ServermanagedPolicy) ששומר במטמון נתוני תגובה של רישיונות, באמצעות AESObfuscator בתור מומלץ מאוד להטמיע את Obfuscator. למידע נוסף, עיינו בקטע הבא.

AESObfuscator

LVL כולל הטמעה מלאה ומומלצת של Obfuscator שנקרא AESObfuscator. ההטמעה משולבת עם אפליקציה לדוגמה של LVL ומשמשת כברירת המחדל של Obfuscator בספרייה.

AESObfuscator מספק ערפול קוד (obfuscation) מאובטח של נתונים באמצעות AES כדי להצפין ולפענח את הנתונים כשהם נכתבים באחסון או קוראים אותם. ההצפנה מתבצעת על ידי Obfuscator באמצעות שלושה שדות נתונים על ידי האפליקציה:

  1. A salt — מערך בייטים אקראיים לשימוש לכל ערפול (obfuscation).
  2. מחרוזת של מזהה אפליקציה, בדרך כלל שם החבילה של האפליקציה.
  3. מחרוזת של מזהה מכשיר, שנגזרת מכמה מקורות ספציפיים למכשיר ככל האפשר, כדי שהיא תהיה ייחודית.

כדי להשתמש ב-AESObfuscator, קודם צריך לייבא אותו לפעילות שלך. הצהרה על פרטי מערך סופי סטטי שיכיל את בייטים ה-salt ולאתחל אותו ב-20 באופן אקראי בייטים שנוצרו על ידי AI.

Kotlin

// Generate 20 random bytes, and put them here.
private val SALT = byteArrayOf(
        -46, 65, 30, -128, -103, -57, 74, -64, 51, 88,
        -95, -45, 77, -117, -36, -113, -11, 32, -64, 89
)

Java

...
    // Generate 20 random bytes, and put them here.
    private static final byte[] SALT = new byte[] {
     -46, 65, 30, -128, -103, -57, 74, -64, 51, 88, -95,
     -45, 77, -117, -36, -113, -11, 32, -64, 89
     };
    ...

בשלב הבא צריך להצהיר על משתנה שמכיל מזהה מכשיר וליצור בשבילו ערך אותו לפי הצורך. לדוגמה, האפליקציה לדוגמה שכלולה ב-LVL שולחת שאילתה להגדרות המערכת android.Settings.Secure.ANDROID_ID, שהוא ייחודי לכל מכשיר.

לתשומת ליבכם: בהתאם לממשקי ה-API שבהם אתם משתמשים, ייתכן שהאפליקציה יצטרך לבקש הרשאות נוספות כדי לקבל מידע ספציפי למכשיר. לדוגמה, כדי לשלוח שאילתה על TelephonyManager כדי לקבל מספר ה-IMEI של המכשיר או נתונים קשורים, האפליקציה תצטרך גם לבקש את ההרשאה android.permission.READ_PHONE_STATE במניפסט.

לפני שמבקשים הרשאות חדשות למטרה הבלעדית של צירוף משתמשים מידע ספציפי למכשיר שישמש בObfuscator, כדאי להביא בחשבון איך פעולה זו עשויה להשפיע על האפליקציה או על הסינון שלה ב-Google Play (מכיוון שהרשאות מסוימות יכולות לגרום לכלי ה-build של ה-SDK להוסיף <uses-feature> המשויך).

לבסוף, בונים מכונה של AESObfuscator ומעבירים את ה-salt, מזהה האפליקציה ומזהה המכשיר. אפשר ליצור את המכונה ישירות, בזמן בניית ה-Policy וה-LicenseChecker. לדוגמה:

Kotlin

    ...
    // Construct the LicenseChecker with a Policy.
    private val checker = LicenseChecker(
            this,
            ServerManagedPolicy(this, AESObfuscator(SALT, packageName, deviceId)),
            BASE64_PUBLIC_KEY
    )
    ...

Java

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

לקבלת דוגמה מלאה, ראו MainActivity באפליקציה לדוגמה של LVL.

בדיקת הרישיון מפעילות

אחרי הטמעה של Policy לניהול הגישה לאפליקציה, השלב הבא הוא להוסיף בדיקת רישיון לאפליקציה, מה שיפעיל שאילתה לשרת הרישוי במקרה הצורך, ומנהל את הגישה לאפליקציה בהתאם תגובת הרישיון. כל העבודה של הוספת בדיקת הרישיון והטיפול בה התגובה מתרחשת בקובץ המקור הראשי Activity.

כדי להוסיף את בדיקת הרישיון ולטפל בתגובה, צריך:

  1. הוספת ייבוא
  2. להטמיע LicenseCheckerCallback ככיתה פרטית פנימית
  3. יצירת מטפל לפרסום מ- LicenseCheckerCallback לשרשור בממשק המשתמש
  4. Instantiate LicenseChecker ו- LicenseCheckerCallback
  5. Call CheckAccess() כדי להפעיל את בדיקת הרישיון
  6. הטמעת המפתח הציבורי לצורך רישוי
  7. קוראים למתודה onDestroy() של LicenseChecker כדי לסגור חיבורי IPC.

הקטעים הבאים מתארים את המשימות האלה.

סקירה כללית של בדיקת רישיונות ותגובה אליהם

ברוב המקרים, כדאי להוסיף את בדיקת הרישיון לחשבון הראשי של האפליקציה Activity, בשיטה onCreate(). הזה מבטיחה שכאשר המשתמש יפעיל את האפליקציה באופן ישיר, בדיקת הרישיון תופעל באופן מיידי. במקרים מסוימים, אפשר להוסיף בדיקות רישיון במערכות מיקומים ספציפיים. לדוגמה, אם האפליקציה כוללת מספר פעילויות רכיבים שאפליקציות אחרות יכולות להתחיל ב-Intent, אתם יכולים להוסיף בדיקות רישיונות לפעילויות האלה.

בדיקת הרישיון מורכבת משתי פעולות עיקריות:

  • קריאה ל-method להפעלת בדיקת הרישיון — ב-LVL, קריאה ל-method checkAccess() של אובייקט LicenseChecker שאתם בונים.
  • קריאה חוזרת (callback) שמחזירה את התוצאה של בדיקת הרישיון. ב-LVL, ממשק LicenseCheckerCallback שאתם מטמיעים. הממשק כולל שתי שיטות: allow() dontAllow(), שמופעלים על ידי הספרייה על סמך התוצאה של בדיקת הרישיון. אתם מיישמים את שתי השיטות האלה בכל לוגיקה שהיא הדרוש לך, כדי לאפשר או לא לאפשר למשתמש גישה לאפליקציה שלך. שימו לב השיטות האלה לא קובעות אם לאפשר גישה – החלטה זו אחראית ליישום של Policy. במקום זאת, methods של האפליקציות פשוט מספקות את התנהגויות האפליקציה שאיך למנוע גישה (ולטפל בשגיאות באפליקציה).

    השיטות allow() ו-dontAllow() מספקות 'סיבה' של התשובה, שיכול להיות אחד מהערכים Policy, LICENSED, NOT_LICENSED או RETRY. במיוחד, עליך לטפל במקרה שבו ה-method מקבלת את התשובה RETRY עבור dontAllow() ומספקת למשתמש "ניסיון חוזר" שייתכן שהסיבה לכך היא שהשירות לא היה זמין במהלך בקשה.

איור 1. סקירה כללית של אינטראקציה טיפוסית של בדיקת רישיון.

התרשים שלמעלה ממחיש איך מתבצעת בדיקת רישיון אופיינית:

  1. קוד בפעילות הראשית של האפליקציה יוצר את LicenseCheckerCallback ו-LicenseChecker אובייקטים. כשיוצרים את LicenseChecker, הקוד מעביר Context, הטמעת Policy לשימוש, וגם המפתח הציבורי של החשבון של בעל התוכן הדיגיטלי לרישוי כפרמטרים.
  2. לאחר מכן הקוד קורא ל-method checkAccess() אובייקט LicenseChecker. הטמעת השיטה מפעילה את Policy כדי לקבוע האם יש תגובת רישיון חוקית ששמורה במטמון באופן מקומי, SharedPreferences.
    • אם כן, לקרוא להטמעה של checkAccess() allow().
    • אחרת, LicenseChecker יוזם בקשה לבדיקת רישיון שנשלחת לשרת הרישוי.

    הערה: שרת הרישוי תמיד מחזיר LICENSED כשמבצעים בדיקת רישיון של טיוטת בקשה.

  3. כשמתקבלת תשובה, LicenseChecker יוצר LicenseValidator ש מאמת את הנתונים של הרישיון החתום ומחלץ את השדות בתשובה, מועברות אל Policy להערכה נוספת.
    • אם הרישיון תקף, Policy ישמור את התגובה במטמון SharedPreferences ומודיע לכלי התיקוף, ואז קורא לפונקציה השיטה allow() באובייקט LicenseCheckerCallback.
    • אם הרישיון לא תקף, נשלחת הודעה מ-Policy לכלי התיקוף, והפעולה הזו קוראת השיטה dontAllow() ב-LicenseCheckerCallback.
  4. במקרה של שגיאה מקומית או שגיאה בחיבור לשרת שניתן לשחזר, למשל כאשר הרשת לא זמין לשליחת הבקשה, LicenseChecker מעביר תשובת RETRY אל באמצעות ה-method processServerResponse() של האובייקט Policy.

    כמו כן, גם אמצעי הקריאה החוזרת (callback) allow() וגם dontAllow() מקבלים ארגומנט reason. הסיבה בשיטה allow() היא בדרך כלל Policy.LICENSED או Policy.RETRY והסיבה dontAllow() היא בדרך כלל Policy.NOT_LICENSED או Policy.RETRY. ערכי התשובות האלה שימושיים כדי שתוכלו להציג תגובה הולמת למשתמש, למשל שליחת תשובה לחצן כאשר dontAllow() מגיב עם Policy.RETRY. יכול להיות שהסיבה לכך היא שהשירות היה לא זמין.

  5. במקרה של שגיאה באפליקציה, למשל כשהאפליקציה מנסה בדיקת הרישיון של שם חבילה לא תקין, LicenseChecker מעביר שגיאה תגובה ל-applicationError() של LicenseCheckerCallback .

שימו לב שבנוסף להתחלת בדיקת הרישיון וטיפול לתוצאות האלה, שמתוארים בסעיפים הבאים, האפליקציה שלכם צריכה גם כדי לספק הטמעת מדיניות, ואם Policy שומרת נתוני תגובות (למשל ServerManagedPolicy), רכיב של Obfuscator.

הוספת ייבוא

קודם כול, פותחים את קובץ הכיתה של הפעילות הראשית וייבוא האפליקציה. LicenseChecker ו-LicenseCheckerCallback מחבילת ה-LVL.

Kotlin

import com.google.android.vending.licensing.LicenseChecker
import com.google.android.vending.licensing.LicenseCheckerCallback

Java

import com.google.android.vending.licensing.LicenseChecker;
import com.google.android.vending.licensing.LicenseCheckerCallback;

אם משתמשים בהטמעת ברירת המחדל של Policy שסופקה עם ה-LVL, ServerמנוהלPolicy, צריך לייבא גם אותו, יחד עם AESObfuscator. אם אתם באמצעות Policy או Obfuscator מותאמים אישית, אפשר לייבא אותם במקום זאת.

Kotlin

import com.google.android.vending.licensing.ServerManagedPolicy
import com.google.android.vending.licensing.AESObfuscator

Java

import com.google.android.vending.licensing.ServerManagedPolicy;
import com.google.android.vending.licensing.AESObfuscator;

הטמעת LicenseCheckerCallback ככיתה פנימית פרטית

LicenseCheckerCallback הוא ממשק שמסופק על ידי ה-LVL לטיפול תוצאה של בדיקת רישיון. כדי לתמוך ברישוי באמצעות ה-LVL, צריך להטמיע את LicenseCheckerCallback וגם את השיטות שלו כדי לאפשר או לא לאפשר גישה לאפליקציה.

התוצאה של בדיקת רישיון היא תמיד קריאה לאחד LicenseCheckerCallback שיטות, שנוצרו על סמך אימות התשובה המטען הייעודי (payload), קוד התגובה של השרת עצמו וכל עיבוד נוסף שמסופק על ידי Policy. האפליקציה יכולה להטמיע את השיטות בכל דרך שנדרשת. לחשבון באופן כללי, רצוי להשתמש בשיטות פשוטות ולהגביל אותן לניהול ממשק המשתמש למצב וליישום. אם ברצונך להוסיף עוד עיבוד של הרישיון על ידי יצירת קשר עם שרת עורפי או החלת אילוצים מותאמים אישית, כדאי לשלב את הקוד הזה ב-Policy במקום הטמענו אותו ב-methods של LicenseCheckerCallback.

ברוב המקרים, עליכם להצהיר על ההטמעה של LicenseCheckerCallback ככיתה פרטית בתוך הכיתה הראשית של האפליקציה שיעור פעילות.

הטמעת השיטות allow() ו-dontAllow() בתור הדרושים. קודם כול, אפשר להשתמש בהתנהגויות פשוטות של טיפול בתוצאות methods, כמו הצגת תוצאת הרישיון בתיבת דו-שיח. כך אפשר לקבל שבו האפליקציה תפעל מוקדם יותר ויכולה לסייע בניפוי באגים. מאוחר יותר, אחרי קבעת בדיוק את הפעולות הרצויות, אפשר להוסיף טיפול מורכב יותר.

הצעות מסוימות לטיפול בתשובות ללא רישיון dontAllow() כוללים את:

  • הצגה של ההודעה 'ניסיון חוזר' תיבת דו-שיח למשתמש, כולל לחצן להפעלת בדיקת רישיון חדש אם ה-reason שסופק הוא Policy.RETRY.
  • הצגת ההודעה 'רכישת האפליקציה הזו' בתיבת דו-שיח, כולל לחצן מקשר את המשתמש לדף הפרטים של האפליקציה ב-Google Play, שממנו יכולים לרכוש את האפליקציה. לקבלת מידע נוסף על האופן שבו מגדירים לקישורים הרלוונטיים, ראו קישור למוצרים שלך.
  • להציג התראת הודעה קופצת שמציינת שהתכונות של מוגבלת מכיוון שהיא לא ברישיון.

הדוגמה הבאה ממחישה איך אפליקציה לדוגמה של LVL מיושמת LicenseCheckerCallback, בשיטות שמציגות את בדיקת הרישיון מניבות

Kotlin

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.
        displayResult(getString(R.string.allow))
    }

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

        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.
            showDialog(DIALOG_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.
            showDialog(DIALOG_GOTOMARKET)
        }
    }
}

Java

private class MyLicenseCheckerCallback implements LicenseCheckerCallback {
    public void allow(int reason) {
        if (isFinishing()) {
            // Don't update UI if Activity is finishing.
            return;
        }
        // Should allow user access.
        displayResult(getString(R.string.allow));
    }

    public void dontAllow(int reason) {
        if (isFinishing()) {
            // Don't update UI if Activity is finishing.
            return;
        }
        displayResult(getString(R.string.dont_allow));

        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.
            showDialog(DIALOG_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.
            showDialog(DIALOG_GOTOMARKET);
        }
    }
}

בנוסף, עליך להטמיע את applicationError() , שה-LVL קורא כדי לאפשר לאפליקציה לטפל בשגיאות שלא ניתן לנסות שוב. לרשימה של שגיאות כאלה, אפשר לעיין בקטע שרת קודי תגובה בחומר העזר בנושא רישוי. אפשר להטמיע את השיטה הנדרשת בכל דרך שהיא. ברוב המקרים, הפרמטר ה-method הזה צריך לתעד את קוד השגיאה ולקרוא ל-dontAllow().

יצירת Handler לפרסום תוכן מ- LicenseCheckerCallback לשרשור בממשק המשתמש

במהלך בדיקת רישיון, ה-LVL מעביר את הבקשה אל Google Play שמטפל בתקשורת עם שרת הרישוי. LVL מעביר את הבקשה דרך IPC אסינכרוני (באמצעות Binder) כך העיבוד והתקשורת ברשת בפועל לא מתבצעים בשרשור שמנוהלות על ידי האפליקציה שלכם. באופן דומה, כשאפליקציית Google Play מקבל את התוצאה, הוא מפעיל שיטת קריאה חוזרת ב-IPC, שבתורה פועל במאגר שרשורים של IPC בתהליך האפליקציה שלכם.

המחלקה LicenseChecker מנהלת את תקשורת ה-IPC של האפליקציה עם אפליקציית Google Play, כולל השיחה ששולחת את הבקשה הקריאה החוזרת שמקבלת את התשובה. LicenseChecker עוקב גם אחרי רישיון פתוח ומנהל את הזמן הקצוב לתפוגה שלהם.

כדי לנהל כראוי את הזמן הקצוב לתפוגה וגם לעבד תשובות נכנסות בלי להשפיע על ה-thread של ממשק המשתמש של האפליקציה, LicenseChecker יוצר שרשור ברקע ביצירת מופע. בשרשור מתבצע כל העיבוד של תוצאות בדיקת רישיונות, אם התוצאה היא תגובה שהתקבלה מהשרת או שגיאה של תפוגת זמן קצוב. בסיום העיבוד, ה-LVL קורא לפונקציה LicenseCheckerCallback methods מהשרשור ברקע.

לגבי הבקשה שלך, המשמעות היא:

  1. במקרים רבים, השיטות של LicenseCheckerCallback יופעלו דרך שרשור ברקע.
  2. השיטות האלה לא יוכלו לעדכן את המצב או להפעיל עיבוד כלשהו שרשור בממשק המשתמש, אלא אם יוצרים מטפל בשרשור של ממשק המשתמש ומקבלים קריאה חוזרת מתווספות ל-Handler.

אם רוצים שה-methods של LicenseCheckerCallback יעדכנו את ה-thread של ממשק המשתמש, ליצור Handler בפעילות הראשית שיטה onCreate(), כפי שמוצג בהמשך. בדוגמה הזו, האפליקציה לדוגמה של ה-LVL LicenseCheckerCallback שיטות (ראו למעלה) מבצעות קריאה ל-displayResult() כדי לעדכן את השרשור בממשק המשתמש דרך אמצעי תשלום אחד (post()).

Kotlin

    private lateinit var handler: Handler

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        handler = Handler()
    }

Java

    private Handler handler;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        ...
        handler = new Handler();
    }

לאחר מכן, בשיטות LicenseCheckerCallback אפשר להשתמש בשיטות Handler כדי לשלוח אובייקטים שניתנים להרצה או לשליחת הודעה ל-handler. כך עושים את זה שכלול ב-LVL מפרסם אובייקט שניתן להריץ ל-handler בשרשור של ממשק המשתמש כדי להציג את סטטוס הרישיון.

Kotlin

private fun displayResult(result: String) {
    handler.post {
        statusText.text = result
        setProgressBarIndeterminateVisibility(false)
        checkLicenseButton.isEnabled = true
    }
}

Java

private void displayResult(final String result) {
        handler.post(new Runnable() {
            public void run() {
                statusText.setText(result);
                setProgressBarIndeterminateVisibility(false);
                checkLicenseButton.setEnabled(true);
            }
        });
    }

Directiate LicenseChecker ו- LicenseCheckerCallback

בחלק של הפעילות הראשית אמצעי תשלום אחד (onCreate()), יצירת מופעים פרטיים של LicenseCheckerCallback ו-LicenseChecker. צריך קודם כל יוצרים מופע של LicenseCheckerCallback, כי צריך להעביר למופע הזה כשקוראים ל-constructor של LicenseChecker.

כשיוצרים את LicenseChecker, צריך להעביר את הפרמטרים הבאים:

  • האפליקציה Context
  • הפניה להטמעה של Policy שצריך להשתמש בה לבדיקת הרישיון. לחשבון ברוב המקרים, צריך להשתמש בהטמעת ברירת המחדל של Policy שמסופקת על ידי ה-LVL, ServerManagedPolicy.
  • משתנה המחרוזת שמכיל את המפתח הציבורי של חשבון בעל האתר שלכם עבור של רישוי.

אם אתם משתמשים ב-ServerManagedPolicy, לא תצטרכו לגשת לכיתה. ישירות, כך שאפשר ליצור אותו ב-constructor של LicenseChecker, כפי שאפשר לראות בדוגמה הבאה. לתשומת ליבכם: צריך להעביר הפניה אל מופע של ערפול קוד (obfuscator) כשיוצרים ServerManagedPolicy.

הדוגמה הבאה מציגה את יצירת המופע של LicenseChecker LicenseCheckerCallback מה-method onCreate() של הפעילות בכיתה.

Kotlin

class MainActivity : AppCompatActivity() {
    ...
    private lateinit var licenseCheckerCallback: LicenseCheckerCallback
    private lateinit var checker: LicenseChecker

    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.
        )
        ...
    }
}

Java

public class MainActivity extends Activity {
    ...
    private LicenseCheckerCallback licenseCheckerCallback;
    private LicenseChecker checker;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        // Construct the LicenseCheckerCallback. The library calls this when done.
        licenseCheckerCallback = new MyLicenseCheckerCallback();

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

חשוב לשים לב ש-LicenseChecker קורא ל-methods LicenseCheckerCallback מממשק המשתמש thread רק אם יש תגובה תקפה של הרישיון ששמורה במטמון באופן מקומי. אם בדיקת הרישיון נשלחת לשרת, הקריאות החוזרות תמיד מגיעות של שרשור ברקע, גם במקרה של שגיאות רשת.

קריאה ל-checkAccess() כדי להפעיל את בדיקת הרישיון

בפעילות הראשית, מוסיפים קריאה ל-method checkAccess() של מופע אחד (LicenseChecker). בשיחה, מעבירים את המופע של LicenseCheckerCallback כפרמטר. אם צריך לטפל במשהו אפקטים מיוחדים בממשק המשתמש או ניהול מצב לפני השיחה, ייתכן שהם יעזרו כדי להפעיל את checkAccess() מ-method של wrapper. לדוגמה, טבלת ה-LVL קריאות לדוגמה של אפליקציות מ-checkAccess() שיטת wrapper doCheck():

Kotlin

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        // Call a wrapper method that initiates the license check
        doCheck()
        ...
    }
    ...
    private fun doCheck() {
        checkLicenseButton.isEnabled = false
        setProgressBarIndeterminateVisibility(true)
        statusText.setText(R.string.checking_license)
        checker.checkAccess(licenseCheckerCallback)
    }

Java

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        // Call a wrapper method that initiates the license check
        doCheck();
        ...
    }
    ...
    private void doCheck() {
        checkLicenseButton.setEnabled(false);
        setProgressBarIndeterminateVisibility(true);
        statusText.setText(R.string.checking_license);
        checker.checkAccess(licenseCheckerCallback);
    }

הטמעת המפתח הציבורי לרישוי

עבור כל אפליקציה, שירות Google Play פועל באופן אוטומטי יוצר זוג מפתחות RSA ציבורי/פרטי של 2048 ביטים שמשמש רישוי וחיוב על רכישות באפליקציות. זוג המפתחות משויך באופן ייחודי תרגום מכונה. למרות שזוג המפתחות משויך לאפליקציה, לא זהה למפתח שבו אתם משתמשים כדי לחתום על האפליקציות שלכם (או שנגזר מהן).

מערכת Google Play Console חושפת את המפתח הציבורי לצורך רישוי המפתח נכנס ל-Play Console, אבל הוא נשאר עם המפתח הפרטי מוסתר מכל המשתמשים במיקום מאובטח. כשאפליקציה מבקשת בדיקת רישיון של אפליקציה שפורסמה בחשבון שלכם, שרת הרישוי חותם על תגובת הרישיון באמצעות המפתח הפרטי של זוג המפתחות של האפליקציה. כשה-LVL מקבל את התשובה, הוא משתמש במפתח הציבורי שסופק לאימות החתימה של תגובת הרישיון.

כדי להוסיף רישיון לאפליקציה, עליך לקבל את מפתח ציבורי לרישוי ומעתיקים אותו לאפליקציה. כך מוצאים המפתח הציבורי של האפליקציה שלך לרישוי:

  1. עוברים אל Google Play Console ונכנסים לחשבון. צריך לוודא שנכנסתם לחשבון שממנו נשלחה האפליקציה הרישוי פורסם (או יפורסם).
  2. בדף הפרטים של האפליקציה, מחפשים את האפשרות Services & ממשקי API ולוחצים עליו.
  3. בקטע שירותים API, לאתר את רישוי בקטע 'חיוב על רכישות באפליקציות'. המפתח הציבורי שלך עבור הרישוי ניתן בשדה מפתח הרישיון שלך לאפליקציה זו.

כדי להוסיף את המפתח הציבורי לאפליקציה, פשוט מעתיקים ומדביקים את מחרוזת המפתח מהשדה לאפליקציה בתור הערך של המשתנה String (מחרוזת) BASE64_PUBLIC_KEY בזמן ההעתקה, צריך לוודא נבחר את כל מחרוזת המפתח, בלי להשמיט תווים.

הנה דוגמה מהאפליקציה לדוגמה של LVL:

Kotlin

private const val BASE64_PUBLIC_KEY = "MIIBIjANBgkqhkiG ... " //truncated for this example
class LicensingActivity : AppCompatActivity() {
    ...
}

Java

public class MainActivity extends Activity {
    private static final String BASE64_PUBLIC_KEY = "MIIBIjANBgkqhkiG ... "; //truncated for this example
    ...
}

קריאה למתודה onDestroy() של LicenseChecker כדי לסגור חיבורי IPC

לבסוף, כדי לאפשר ל-LVL לנקות לפני הבקשה Context שינויים, הוספת קריאה ל-LicenseChecker שיטה אחת (onDestroy()) מתוך הפעילות שלך הטמעת onDestroy(). השיחה גורמת LicenseChecker כדי לסגור כראוי כל חיבור IPC פתוח ל-Google Play ILicensingService של האפליקציה ומסירה כל אזכור מקומי של השירות ו-handler.

קריאה ל-method של onDestroy() של LicenseChecker נכשלה עלולות לגרום לבעיות במחזור החיים של האפליקציה. לדוגמה, אם שהמשתמש משנה את כיוון המסך בזמן שבדיקת הרישיון פעילה, האפליקציה Context מושמד. אם האפליקציה שלכם לא תסגור כראוי את חיבור ה-IPC של LicenseChecker, האפליקציה שלך תקרוס כאשר מתקבלת התשובה. באופן דומה, אם המשתמש יוצא מהאפליקציה בזמן שמתבצעת בדיקת רישיון, האפליקציה שלך תקרוס את התשובה, אלא אם היא קראה כראוי השיטה onDestroy() של LicenseChecker כדי להתנתק מהשירות.

הנה דוגמה מהאפליקציה לדוגמה שכלולה ב-LVL, mChecker הוא המופע של LicenseChecker:

Kotlin

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

Java

    @Override
    protected void onDestroy() {
        super.onDestroy();
        checker.onDestroy();
        ...
    }

אם בחרת להרחיב או לשנות את LicenseChecker, יכול להיות שיהיה צורך לבצע קריאה השיטה finishCheck() של LicenseChecker, כדי לנקות IPC פתוח בחיבורים.

יישום DeviceLimiter

במקרים מסוימים, ייתכן שתרצו שה-Policy יגביל את מספר מכשירים שמורשים להשתמש ברישיון יחיד. זה ימנע ממשתמש מהעברת אפליקציה מורשית למספר מכשירים ושימוש במכשירים האלה עם אותו מספר חשבון. כמו כן, היא תמנע משתמש מ'שיתוף' את הבקשה באמצעות פרטי החשבון שמשויכים לרישיון לאנשים אחרים, שיכולים להיכנס לאחר מכן החשבון במכשירים שלהם ולגשת לרישיון לאפליקציה.

LVL תומך ברישוי לכל מכשיר באמצעות בממשק DeviceLimiter, שמצהיר על שיטה אחת, allowDeviceAccess(). כאשר LicenseValidator מטפל בתגובה משרת הרישוי הוא מבצע קריאה ל-allowDeviceAccess(), ומעביר מחרוזת מזהה המשתמש חולפת מהתגובה.

אם לא רוצים לתמוך בהגבלת מספר המכשירים, אין עבודה חובה – הכיתה LicenseChecker משתמשת באופן אוטומטי בברירת מחדל שנקראת NullDeviceLimiter. כפי שרמז השם, NullDeviceLimiter הוא 'לא תפעול' מחלקה שהשיטה allowDeviceAccess() שלה פשוט מחזירה תגובת LICENSED לכל המשתמשים והמכשירים.

זהירות: רישוי לפי מכשיר לא מומלץ עבור רוב האפליקציות כי:

  • צריך לספק שרת עורפי כדי לנהל משתמשים ומכשירים מיפוי, ו
  • היא עלולה לגרום בטעות לדחיית הגישה של משתמש אל אפליקציה שהם רכשו באופן חוקי במכשיר אחר.

ערפול הקוד (obfuscation)

כדי להבטיח את אבטחת האפליקציה, במיוחד באפליקציות בתשלום המשתמשת ברישוי ו/או באילוצים והגנות מותאמים אישית, חשוב מאוד לערפל את קוד האפליקציה שלכם. ערפול קוד (obfuscation) תקין מקשה על משתמש זדוני להסיר את הידור של היישום bytecode, לשנות אותו — למשל על ידי הסרת בדיקת הרישיון — ואז להדר אותו מחדש.

יש כמה תוכניות מערפול קוד (obfuscator) זמינות לאפליקציות ל-Android, כולל ProGuard, שכולל גם לתכונות לאופטימיזציה של קוד. שימוש ב-ProGuard או בתוכנה דומה לערפול קוד (obfuscation) הקוד מומלץ מאוד לכל האפליקציות שמשתמשות ב-Google Play רישיון.

פרסום אפליקציה ברישיון

בסיום הבדיקה של הטמעת הרישיון, תהיו מוכנים לפרסם את האפליקציה ב-Google Play. פועלים לפי השלבים הרגילים כדי להכין את הבקשה, לחתום עליה ולאחר מכן לפרסם אותה.

היכן לקבל תמיכה

אם יש לך שאלות או נתקלת בבעיות במהלך הטמעה או פריסה בפרסום באפליקציות שלך, עליך להשתמש במשאבי התמיכה המפורטים בטבלה שלמטה. אם תעבירו את השאילתות לפורום המתאים, תוכלו לקבל התמיכה הנדרשת מהר יותר.

טבלה 2. מקורות מידע לתמיכה למפתחים של שירות הרישוי של Google Play.

סוג התמיכה משאב טווח הנושאים
בעיות פיתוח ובדיקה קבוצות Google: android-developers הורדה ושילוב של LVL, פרויקטים של ספריות, Policy שאלות, רעיונות לחוויית משתמש, טיפול בתשובות, Obfuscator, IPC, בדיקה הגדרת סביבה
Stack Overflow: http://stackoverflow.com/questions/TAG/android
בעיות בחשבונות, בפרסום ובפריסה ב-Google Play פורום העזרה חשבונות של בעל תוכן דיגיטלי, זוג מפתחות רישוי, חשבונות בדיקה, שרת תגובות, תגובות לבדיקה, פריסת אפליקציות ותוצאות
שוק שאלות נפוצות על תמיכה בנושא רישוי
מעקב אחר בעיות LVL רישוי מעקב אחרי בעיות בפרויקט דוחות על באגים ובעיות שקשורים באופן ספציפי למחלקות של קוד המקור LVL והטמעות ממשקים

למידע כללי על פרסום פוסטים בקבוצות שצוינו למעלה, ראו מקורות מידע לקהילה בדף 'משאבי תמיכה למפתחים'.

משאבים נוספים

האפליקציה לדוגמה הכלולה ב-LVL מספקת דוגמה מלאה לאופן שבו להתחיל בדיקת רישיון ולטפל בתוצאה, כיתה אחת (MainActivity).