Cảnh báo: Khi ứng dụng thực hiện quy trình xác minh giấy phép phía máy khách, những kẻ tấn công có thể dễ dàng sửa đổi hoặc xoá logic được liên kết với quy trình xác minh này.
Vì lý do này, bạn rất nên thực hiện quy trình xác minh giấy phép phía máy chủ.
Sau khi thiết lập tài khoản nhà xuất bản và môi trường phát triển (xem phần Thiết lập để cấp phép), bạn có thể thêm quy trình xác minh giấy phép vào ứng dụng bằng Thư viện xác minh giấy phép (LVL).
Để thêm quy trình xác minh giấy phép (LVL):
- Thêm quyền cấp phép trong tệp kê khai của ứng dụng.
- Triển khai Chính sách — bạn có thể chọn một trong các phương pháp triển khai đầy đủ được cung cấp trong LVL hoặc tạo phương thức triển khai của riêng bạn.
- Triển khai Trình làm rối (Obfuscator) nếu
Policy
của bạn sẽ lưu mọi dữ liệu phản hồi giấy phép vào bộ nhớ đệm. - Thêm mã để kiểm tra giấy phép trong lớp Activity chính của ứng dụng.
- Triển khai DeviceLimiter (không bắt buộc và không nên dùng cho hầu hết ứng dụng).
Các phần dưới đây mô tả những việc cần làm này. Sau khi hoàn tất quá trình tích hợp, bạn sẽ có thể biên dịch thành công ứng dụng và có thể bắt đầu kiểm thử như được mô tả trong phần Thiết lập môi trường kiểm thử.
Để biết thông tin tổng quan về bộ tệp nguồn đầy đủ có trong LVL, hãy xem phần Tóm tắt về các lớp và giao diện LVL.
Thêm quyền cấp phép
Để dùng ứng dụng Google Play cho việc gửi yêu cầu kiểm tra giấy phép đến máy chủ, ứng dụng của bạn phải yêu cầu quyền thích hợp, com.android.vending.CHECK_LICENSE
. Nếu ứng dụng của bạn không khai báo quyền cấp phép nhưng cố gắng bắt đầu kiểm tra giấy phép, thì LVL sẽ gửi ra một trường hợp ngoại lệ về bảo mật.
Để yêu cầu quyền cấp phép trong ứng dụng của bạn, hãy khai báo phần tử <uses-permission>
làm phần tử con của <manifest>
như sau:
<uses-permission
android:name="com.android.vending.CHECK_LICENSE" />
Ví dụ dưới đây là cách ứng dụng mẫu LVL khai báo quyền:
<?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>
Lưu ý: Hiện tại, bạn không thể khai báo quyền CHECK_LICENSE
trong tệp kê khai của dự án thư viện LVL vì Bộ công cụ SDK sẽ không hợp nhất quyền này vào tệp kê khai của các ứng dụng phụ thuộc. Thay vào đó, bạn phải khai báo quyền trong tệp kê khai của từng ứng dụng phụ thuộc.
Triển khai chính sách
Dịch vụ cấp phép của Google Play không tự xác định liệu một người dùng cụ thể với giấy phép cụ thể có nên được cấp quyền truy cập vào ứng dụng của bạn hay không.
Thay vào đó, quy trình triển khai Policy
mà bạn cung cấp trong ứng dụng sẽ thực hiện trách nhiệm này.
Chính sách là một giao diện do LVL khai báo được thiết kế để giữ lại logic của ứng dụng nhằm cho phép hoặc không cho phép người dùng truy cập, dựa trên kết quả kiểm tra giấy phép. Để sử dụng LVL, ứng dụng của bạn phải đưa ra một quy trình triển khai của Policy
.
Giao diện Policy
khai báo hai phương thức allowAccess()
và processServerResponse()
. Các phương thức này được một thực thể LicenseChecker
gọi khi xử lý phản hồi của máy chủ cấp phép. Phương thức này cũng khai báo một enum có tên là LicenseResponse
, trong đó chỉ định giá trị phản hồi giấy phép được truyền trong các lệnh gọi đến processServerResponse()
.
processServerResponse()
cho phép bạn xử lý trước dữ liệu phản hồi thô nhận được từ máy chủ cấp phép trước khi xác định việc có cấp quyền truy cập hay không.Quy trình triển khai thông thường sẽ trích xuất một số hoặc tất cả trường trong nội dung phản hồi giấy phép và lưu trữ dữ liệu cục bộ trên một cửa hàng cố định, chẳng hạn như thông qua bộ nhớ
SharedPreferences
, để đảm bảo rằng dữ liệu có thể truy cập được thông qua các lệnh gọi ứng dụng và chu kỳ nguồn của thiết bị. Ví dụ:Policy
sẽ duy trì dấu thời gian của lần kiểm tra giấy phép thành công mới nhất, số lần thử lại, thời hạn hiệu lực của giấy phép và các thông tin tương tự trong một cửa hàng cố định, thay vì đặt lại các giá trị đó mỗi khi chạy ứng dụng.Khi lưu trữ cục bộ dữ liệu phản hồi,
Policy
phải đảm bảo rằng dữ liệu đó đã được làm rối mã nguồn (hãy xem bài viết Triển khai Trình làm rối mã nguồn bên dưới).allowAccess()
sẽ xác định việc có cấp cho người dùng quyền truy cập vào ứng dụng hay không, dựa trên mọi dữ liệu phản hồi giấy phép hiện có (từ máy chủ cấp phép hoặc từ bộ nhớ đệm) hoặc các thông tin cụ thể về ứng dụng khác. Ví dụ: quy trình triển khaiallowAccess()
có thể tính đến các tiêu chí bổ sung như mức sử dụng hoặc dữ liệu khác được truy xuất từ máy chủ phụ trợ. Trong mọi trường hợp, quy trình triển khaiallowAccess()
sẽ chỉ trả vềtrue
nếu người dùng được cấp phép sử dụng ứng dụng, như được xác định bởi máy chủ cấp phép hoặc nếu có sự cố tạm thời về mạng hoặc hệ thống khiến quá trình kiểm tra giấy phép không thể hoàn tất. Trong những trường hợp như vậy, quy trình triển khai của bạn có thể duy trì số lượng phản hồi thử lại và tạm thời cho phép truy cập cho đến khi quá trình kiểm tra giấy phép tiếp theo hoàn tất.
Để đơn giản hoá quá trình thêm giấy phép vào ứng dụng cũng như minh hoạ cách nên thiết kế một Policy
, LVL có 2 cách triển khai Policy
đầy đủ để bạn có thể điều chỉnh theo nhu cầu của mình hoặc dùng ngay mà không cần sửa đổi:
- ServerManagedPolicy, một
Policy
linh hoạt sử dụng các chế độ cài đặt do máy chủ cung cấp và phản hồi được lưu vào bộ nhớ đệm để quản lý quyền truy cập trên nhiều điều kiện mạng, và - StrictPolicy không lưu bất kỳ dữ liệu phản hồi nào vào bộ nhớ đệm và chỉ cho phép truy cập nếu máy chủ trả về một phản hồi đã được cấp phép.
Đối với hầu hết ứng dụng, bạn nên dùng ServerManagedPolicy. ServerManagedPolicy là LVL mặc định và được tích hợp với ứng dụng mẫu LVL.
Nguyên tắc áp dụng chính sách tuỳ chỉnh
Trong quá trình triển khai việc cấp phép, bạn có thể dùng một trong các chính sách hoàn chỉnh được cung cấp trong LVL (ServerManagedPolicy hay StrictPolicy) hoặc bạn có thể tạo một chính sách tuỳ chỉnh. Bất kỳ loại chính sách tuỳ chỉnh nào cũng có một số điểm thiết kế quan trọng để bạn có thể hiểu và điều chỉnh trong quá trình triển khai.
Máy chủ cấp phép áp dụng các giới hạn yêu cầu chung để chống lại việc lạm dụng các tài nguyên có thể dẫn đến sự cố từ chối dịch vụ. Khi một ứng dụng vượt quá giới hạn yêu cầu, máy chủ cấp phép sẽ trả về phản hồi 503. Phản hồi này sẽ được truyền cho ứng dụng của bạn dưới dạng lỗi máy chủ thông thường. Điều đó có nghĩa là người dùng sẽ không nhận được phản hồi giấy phép nào cho đến khi giới hạn được đặt lại, dẫn đến việc họ có thể sẽ bị ảnh hưởng trong thời gian không xác định.
Nếu đang thiết kế một chính sách tuỳ chỉnh thì bạn nên làm như sau với Policy
:
- Lưu vào bộ nhớ đệm (và làm rối mã nguồn đúng cách) nội dung phản hồi giấy phép thành công gần đây nhất trong bộ nhớ cục bộ ổn định.
- Trả về nội dung phản hồi đã lưu vào bộ nhớ đệm đối với mọi quá trình kiểm tra giấy phép thay vì gửi yêu cầu đến máy chủ cấp phép, miễn là nội dung phản hồi được lưu vào bộ nhớ đệm đó là hợp lệ.
Bạn nên đặt thời hạn phản hồi theo
VT
bổ sung do máy chủ cung cấp. Hãy xem phần Thông tin bổ sung về phản hồi của máy chủ để biết thêm thông tin. - Sử dụng khoảng thời gian đợi luỹ thừa nếu có lỗi xảy ra khi thử lại bất kỳ yêu cầu nào. Xin lưu ý rằng ứng dụng Google Play tự động thử lại các yêu cầu không thành công, vì vậy trong hầu hết trường hợp,
Policy
của bạn không cần phải thử lại các yêu cầu này. - Cung cấp một "thời gian gia hạn" cho phép người dùng truy cập vào ứng dụng trong một khoảng thời gian hoặc số lần sử dụng hạn chế trong khi ứng dụng đang thử lại quá trình kiểm tra giấy phép. Thời gian gia hạn sẽ mang lại lợi ích cho người dùng bằng cách cho phép họ truy cập cho đến khi hoàn tất thành công bước kiểm tra giấy phép tiếp theo. Việc này cũng có lợi cho bạn nhờ việc đặt một giới hạn cố định về quyền truy cập vào ứng dụng khi không có phản hồi giấy phép hợp lệ nào.
Bạn cần thiết kế Policy
theo các nguyên tắc nêu trên để đảm bảo trải nghiệm tốt nhất có thể cho người dùng, đồng thời có thể kiểm soát hiệu quả ứng dụng ngay cả trong các điều kiện lỗi.
Xin lưu ý rằng mọi Policy
đều có thể dùng chế độ cài đặt do máy chủ cấp phép cung cấp để giúp quản lý tính hợp lệ và thao tác lưu vào bộ nhớ đệm, thời gian gia hạn thử lại và nhiều tác vụ khác. Việc trích xuất các chế độ cài đặt do máy chủ cung cấp rất đơn giản mà bạn nên tận dụng triệt để. Hãy xem cách triển khai ServerManagedPolicy để biết ví dụ về cách trích xuất và sử dụng các tính năng bổ sung. Để biết danh sách các chế độ cài đặt máy chủ và thông tin về cách sử dụng, hãy xem phần Thông tin bổ sung về phản hồi của máy chủ.
ServerManagedPolicy
LVL bao gồm một quy trình triển khai đầy đủ và được đề xuất của giao diện Policy
có tên là ServerManagedPolicy. Quá trình triển khai được tích hợp với các lớp LVL và đóng vai trò là Policy
mặc định trong thư viện.
ServerManagedPolicy sẽ cung cấp tất cả lượt xử lý phản hồi giấy phép và thử lại. Bộ nhớ đệm này lưu trữ cục bộ tất cả dữ liệu phản hồi vào bộ nhớ đệm trong tệp SharedPreferences
, gây khó khăn cho quá trình triển khai Obfuscator
của ứng dụng. Điều này đảm bảo rằng dữ liệu phản hồi giấy phép sẽ được bảo mật và duy trì trên các chu kỳ nguồn của thiết bị. ServerManagedPolicy sẽ cung cấp những cách triển khai cụ thể của các phương thức giao diện processServerResponse()
và allowAccess()
, đồng thời bao gồm một tập hợp các phương thức và loại hỗ trợ để quản lý phản hồi của giấy phép.
Quan trọng hơn, một đặc điểm chính của ServerManagedPolicy là sử dụng các chế độ cài đặt do máy chủ cung cấp làm cơ sở quản lý việc cấp phép trong suốt kỳ hạn hoàn tiền của ứng dụng cũng như thông qua các điều kiện lỗi và mạng khác nhau.
Khi một ứng dụng liên hệ với máy chủ Google Play để kiểm tra giấy phép, máy chủ sẽ thêm một số tuỳ chọn cài đặt dưới dạng cặp khoá-giá trị trong trường bổ sung của một số loại nội dung phản hồi giấy phép nhất định. Ví dụ: máy chủ cung cấp các giá trị được đề xuất cho thời hạn hiệu lực của giấy phép, thời gian gia hạn thử lại và số lần thử lại tối đa được phép cùng nhiều giá trị khác. ServerManagedPolicy sẽ trích xuất các giá trị từ nội dung phản hồi giấy phép trong phương thức processServerResponse()
và kiểm tra các giá trị đó trong phương thức allowAccess()
. Để biết danh sách các chế độ cài đặt do máy chủ cung cấp được ServerManagedPolicy sử dụng, hãy xem phần Thông tin bổ sung về phản hồi của máy chủ.
Để việc sử dụng chế độ cài đặt giấy phép của máy chủ Google Play được thuận tiện, đạt hiệu suất tốt nhất và lợi ích đi kèm, bạn rất nên dùng ServerManagedPolicy để cấp phép Policy
.
Nếu lo ngại về tính bảo mật của việc dữ liệu phản hồi giấy phép được lưu trữ cục bộ trong SharedPreferences
, thì bạn có thể sử dụng thuật toán làm rối mã nguồn mạnh hơn hoặc thiết kế một Policy
nghiêm ngặt hơn mà không lưu trữ dữ liệu giấy phép. LVL bao gồm một ví dụ về Policy
như vậy — hãy xem phần StrictPolicy để biết thêm thông tin.
Để sử dụng ServerManagedPolicy, bạn chỉ cần nhập thuộc tính này vào Activity, tạo một thực thể và truyền nội dung tham chiếu đến thực thể đó khi tạo LicenseChecker
. Hãy xem bài viết Tạo thực thể LicenseChecker và LicenseCheckerCallback để biết thêm thông tin.
StrictPolicy
LVL bao gồm một phương thức triển khai đầy đủ thay thế cho giao diện Policy
có tên là StrictPolicy. Việc triển khai StrictPolicy cung cấp một Chính sách hạn chế hơn so với ServerManagedPolicy, trong đó chính sách không cho phép người dùng truy cập vào ứng dụng trừ khi máy chủ nhận được phản hồi giấy phép tại thời điểm truy cập cho biết rằng người dùng được cấp phép.
Đặc điểm chính của StrictPolicy là không lưu trữ cục bộ bất kỳ dữ liệu phản hồi giấy phép nào trong một cửa hàng cố định. Vì không có dữ liệu nào được lưu trữ, nên bạn không thể theo dõi yêu cầu thử lại và không thể sử dụng các phản hồi đã lưu vào bộ nhớ đệm để thực hiện kiểm tra giấy phép. Policy
chỉ cho phép truy cập nếu:
- Máy chủ cấp phép nhận được phản hồi giấy phép, và
- Nội dung phản hồi giấy phép cho biết rằng người dùng được cấp phép để truy cập vào ứng dụng.
Việc sử dụng StrictPolicy là phù hợp nếu mối quan tâm chính của bạn là đảm bảo rằng trong mọi trường hợp có thể, sẽ không có người dùng nào được phép truy cập vào ứng dụng trừ khi người dùng được xác nhận là đã được cấp phép tại thời điểm sử dụng. Ngoài ra, tính bảo mật của Chính sách này có phần cao hơn so với ServerManagedPolicy — vì không có dữ liệu nào được lưu cục bộ vào bộ nhớ đệm nên người dùng đáng ngờ tuyệt đối không thể can thiệp vào dữ liệu này để có được quyền truy cập vào ứng dụng.
Đồng thời, Policy
này cũng gây trở ngại đối với người dùng thông thường. Tính bảo mật cao hơn có nghĩa là họ sẽ không thể truy cập vào ứng dụng khi không có sẵn kết nối mạng (di động hoặc Wi-Fi). Một tác dụng phụ khác là ứng dụng sẽ gửi thêm yêu cầu kiểm tra giấy phép đến máy chủ, vì không thể sử dụng nội dung phản hồi đã lưu vào bộ nhớ đệm.
Nhìn chung, có thể thấy rằng chính sách này thoả hiệp một phần sự tiện lợi của người dùng để đổi lấy sự bảo mật và kiểm soát tuyệt đối với quyền truy cập. Hãy cân nhắc kỹ sự đánh đổi trước khi sử dụng Policy
này.
Để sử dụng StrictPolicy, bạn chỉ cần nhập thuộc tính này vào Activity, tạo một thực thể và chuyển nội dung tham chiếu đến thực thể đó khi tạo LicenseChecker
. Hãy xem bài viết về Tạo thực thể LicenseChecker và LicenseCheckerCallback để biết thêm thông tin.
Cách triển khai Policy
thông thường cần lưu dữ liệu phản hồi giấy phép của một ứng dụng vào cửa hàng cố định để bạn có thể truy cập vào dữ liệu này qua các lệnh gọi ứng dụng và chu kỳ nguồn của thiết bị. Ví dụ: Policy
sẽ duy trì dấu thời gian của lần kiểm tra giấy phép thành công gần đây nhất, số lần thử lại, thời hạn hiệu lực của giấy phép và thông tin tương tự trong một cửa hàng cố định, thay vì đặt lại các giá trị đó mỗi khi chạy ứng dụng. Policy
mặc định có trong LVL, ServerManagedPolicy, sẽ lưu trữ dữ liệu phản hồi giấy phép trong một thực thể SharedPreferences
, để đảm bảo dữ liệu luôn ổn định.
Vì Policy
sẽ dùng dữ liệu phản hồi giấy phép đã lưu trữ để xác định liệu có cho phép hay không cho phép truy cập vào ứng dụng, nên phải đảm bảo rằng mọi dữ liệu được lưu trữ đều an toàn và không để người dùng gốc sử dụng lại hoặc làm giả trên một thiết bị. Cụ thể, Policy
phải luôn làm rối mã nguồn trước khi lưu trữ bằng cách sử dụng khoá dành riêng cho ứng dụng và thiết bị. Việc làm rối mã nguồn bằng cách sử dụng một khoá cho cả ứng dụng và thiết bị cụ thể là rất quan trọng vì việc này sẽ ngăn việc chia sẻ dữ liệu xáo trộn giữa các ứng dụng và thiết bị.
LVL hỗ trợ ứng dụng lưu trữ dữ liệu phản hồi giấy phép một cách an toàn, ổn định. Trước tiên, ứng dụng này cung cấp giao diện Obfuscator
cho phép ứng dụng cung cấp thuật toán làm rối mã nguồn cho lựa chọn của dữ liệu đã lưu trữ. Dựa trên đó, LVL cung cấp lớp trợ giúp PreferenceObfuscator, lớp này xử lý hầu hết công việc gọi lớp Obfuscator
của ứng dụng cũng như đọc và ghi dữ liệu bị làm rối mã nguồn trong một thực thể SharedPreferences
.
LVL triển khai đầy đủ Obfuscator
gọi là AESObfuscator, sử dụng phương thức mã hoá AES để làm rối dữ liệu. Bạn có thể dùng AESObfuscator trong ứng dụng mà không cần sửa đổi hoặc bạn có thể điều chỉnh theo nhu cầu. Nếu bạn đang dùng một Policy
(chẳng hạn như ServerManagedPolicy) để lưu dữ liệu phản hồi giấy phép vào bộ nhớ đệm, thì chúng tôi khuyên bạn nên dùng AESObfuscator làm cơ sở cho hoạt động triển khai Obfuscator
Để biết thêm thông tin, hãy xem phần tiếp theo.
AESObfuscator
LVL bao gồm một cách triển khai đầy đủ và được đề xuất của giao diện Obfuscator
có tên là AESObfuscator. Hoạt động triển khai được tích hợp với ứng dụng mẫu LVL và đóng vai trò là Obfuscator
mặc định trong thư viện.
AESObfuscator cung cấp tính năng làm rối mã nguồn dữ liệu một cách an toàn bằng cách sử dụng AES để mã hoá và giải mã dữ liệu khi dữ liệu được ghi hoặc đọc từ bộ nhớ.
Obfuscator
đã chạy quá trình mã hoá bằng ba trường dữ liệu do ứng dụng cung cấp:
- Dữ liệu ngẫu nhiên — một chuỗi các byte ngẫu nhiên để sử dụng cho mỗi trường hợp làm rối (hoặc gỡ rối).
- Chuỗi giá trị nhận dạng ứng dụng, thường là tên gói của ứng dụng.
- Chuỗi giá trị nhận dạng thiết bị, được lấy từ nhiều nguồn dành riêng cho thiết bị nhất có thể nhằm giúp chuỗi trở nên độc nhất.
Để sử dụng AESObfuscator, trước tiên, hãy nhập AESObscscator vào Activity. Khai báo một mảng static final riêng tư để giữ các byte dữ liệu ngẫu nhiên và khởi động mảng đó qua 20 byte được tạo ngẫu nhiên.
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 }; ...
Tiếp theo, hãy khai báo biến để giữ một giá trị nhận dạng thiết bị và tạo giá trị cho biến theo cách cần thiết. Ví dụ: ứng dụng mẫu có trong LVL truy vấn các chế độ cài đặt hệ thống cho android.Settings.Secure.ANDROID_ID
, mỗi chế độ là duy nhất trên mỗi thiết bị.
Xin lưu ý rằng tuỳ thuộc vào các API bạn dùng, ứng dụng của bạn có thể cần yêu cầu các quyền bổ sung để có được thông tin dành riêng cho thiết bị.
Ví dụ: để truy vấn TelephonyManager
để lấy IMEI của thiết bị hoặc dữ liệu có liên quan, ứng dụng cũng cần yêu cầu quyền android.permission.READ_PHONE_STATE
trong tệp kê khai.
Trước khi yêu cầu các quyền mới cho mục đích duy nhất là thu thập thông tin về thiết bị cụ thể để sử dụng trong Obfuscator
, hãy cân nhắc tác động của việc này lên ứng dụng của bạn hoặc việc lọc ứng dụng trên Google Play (vì một số quyền có thể khiến các công cụ xây dựng SDK thêm <uses-feature>
liên quan).
Cuối cùng, hãy tạo một thực thể của AESObfuscator, chuyển dữ liệu ngẫu nhiên, giá trị nhận dạng ứng dụng và giá trị nhận dạng thiết bị. Bạn có thể tạo trực tiếp thực thể đó trong khi tạo Policy
và LicenseChecker
. Ví dụ:
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. ); ...
Để biết ví dụ hoàn chỉnh, hãy xem MainActivity trong ứng dụng mẫu LVL.
Kiểm tra Giấy phép của Activity
Sau khi đã triển khai Policy
để quản lý quyền truy cập vào ứng dụng, bạn hãy thêm chế độ kiểm tra giấy phép vào ứng dụng của bạn. Công cụ này sẽ bắt đầu một truy vấn đối với máy chủ cấp phép nếu cần thiết và quản lý quyền truy cập vào ứng dụng dựa trên dữ liệu phản hồi giấy phép. Bạn cần thực hiện mọi quy trình để kiểm tra giấy phép và xử lý phản hồi trong tệp nguồn Activity
chính.
Để thêm chế độ kiểm tra giấy phép và xử lý phản hồi, bạn phải:
- Thêm các lệnh nhập
- Triển khai LicenseCheckerCallback dưới dạng lớp bên trong riêng tư
- Tạo Trình xử lý để đăng từ LicenseCheckerCallback lên luồng (thread) giao diện người dùng
- Tạo thực thể LicenseChecker và LicenseCheckerCallback
- Gọi CheckAccess() để bắt đầu kiểm tra giấy phép
- Nhúng khoá công khai để cấp phép
- Gọi phương thức của onDestroy() LicenseChecker để đóng các kết nối IPC.
Các phần dưới đây mô tả những việc cần làm này.
Tổng quan về quy trình kiểm tra và phản hồi giấy phép
Trong hầu hết trường hợp, bạn nên thêm chế độ kiểm tra giấy phép vào Activity
chính của ứng dụng, trong phương thức onCreate()
. Việc này đảm bảo rằng khi người dùng chạy trực tiếp ứng dụng của bạn, quá trình kiểm tra giấy phép sẽ được gọi ngay lập tức. Trong một số trường hợp, bạn cũng có thể thêm chế độ kiểm tra giấy phép ở các vị trí khác. Ví dụ: nếu ứng dụng của bạn bao gồm nhiều thành phần Activity mà các ứng dụng khác có thể bắt đầu trước Intent
, thì bạn có thể thêm các bước kiểm tra giấy phép trong các Activity đó.
Quy trình kiểm tra giấy phép bao gồm hai hành động chính:
- Lệnh gọi đến một phương thức để bắt đầu kiểm tra giấy phép — trong LVL, đây là lệnh gọi đến phương thức
checkAccess()
của đối tượngLicenseChecker
mà bạn tạo. - Lệnh gọi lại trong đó trả về kết quả kiểm tra giấy phép. Trong LVL, đây là giao diện
LicenseCheckerCallback
mà bạn triển khai. Giao diện khai báo hai phương thức,allow()
vàdontAllow()
, được thư viện gọi dựa trên kết quả kiểm tra giấy phép. Bạn triển khai hai phương thức này với bất kỳ logic nào bạn cần để cho phép hoặc không cho phép người dùng truy cập vào ứng dụng của bạn. Xin lưu ý rằng các phương thức này không xác định việc có cho phép truy cập hay không. Việc xác định đó là trách nhiệm triển khaiPolicy
của bạn. Thay vào đó, các phương thức này chỉ cung cấp hành vi của ứng dụng để làm thế nào cho phép và không cho phép truy cập (và xử lý các lỗi của ứng dụng).Phương thức
allow()
vàdontAllow()
cung cấp "lý do" cho nội dung phản hồi, có thể là một trong các giá trịPolicy
,LICENSED
,NOT_LICENSED
hoặcRETRY
. Cụ thể, bạn cần xử lý trường hợp mà phương thức này nhận được phản hồiRETRY
chodontAllow()
và cung cấp nút "Thử lại" cho người dùng. Trường hợp này có thể đã xảy ra vì dịch vụ không sẵn có trong quá trình yêu cầu.
Sơ đồ trên cho thấy cách thức hoạt động của quy trình kiểm tra giấy phép thông thường:
- Mã trong mục Activity chính của ứng dụng tạo bản sao của các đối tượng
LicenseCheckerCallback
vàLicenseChecker
. Khi tạoLicenseChecker
, mã sẽ chuyển vàoContext
, phương thức triển khaiPolicy
để sử dụng và khoá công khai của tài khoản nhà xuất bản để cấp phép dưới dạng tham số. - Sau đó, mã này sẽ gọi phương thức
checkAccess()
trên đối tượngLicenseChecker
. Việc triển khai phương thức này sẽ gọiPolicy
để xác định liệu có phản hồi giấy phép hợp lệ được lưu vào bộ nhớ đệm cục bộ trongSharedPreferences
hay không.- Nếu có thì quá trình triển khai
checkAccess()
sẽ gọiallow()
. - Nếu không thì
LicenseChecker
sẽ bắt đầu một yêu cầu kiểm tra giấy phép được gửi đến máy chủ cấp phép.
Lưu ý: Máy chủ cấp phép luôn trả về
LICENSED
khi bạn kiểm tra giấy phép của một ứng dụng nháp. - Nếu có thì quá trình triển khai
- Khi nhận được phản hồi,
LicenseChecker
sẽ tạo một LicenseValidator để xác minh dữ liệu giấy phép đã ký và trích xuất các trường của phản hồi, sau đó chuyển các trường đó đếnPolicy
của bạn để đánh giá thêm.- Nếu giấy phép hợp lệ thì
Policy
sẽ lưu nội dung phản hồi trongSharedPreferences
vào bộ nhớ đệm và thông báo cho trình xác thực. Sau đó, trình xác thực này sẽ gọi phương thứcallow()
trên đối tượngLicenseCheckerCallback
. - Nếu giấy phép không hợp lệ thì
Policy
sẽ thông báo cho trình xác thực. Trình xác thực sẽ gọi phương thứcdontAllow()
trênLicenseCheckerCallback
.
- Nếu giấy phép hợp lệ thì
- Trong trường hợp lỗi cục bộ hoặc lỗi máy chủ có thể khôi phục, chẳng hạn như khi không có mạng để gửi yêu cầu,
LicenseChecker
sẽ chuyển phản hồiRETRY
đến phương thứcprocessServerResponse()
của đối tượngPolicy
.Ngoài ra, cả hai phương thức gọi lại
allow()
vàdontAllow()
đều nhận được một đối sốreason
. Lý do của phương thứcallow()
thường làPolicy.LICENSED
hoặcPolicy.RETRY
và lý dodontAllow()
thường làPolicy.NOT_LICENSED
hoặcPolicy.RETRY
. Các giá trị phản hồi này hữu ích để bạn có thể hiện một phản hồi thích hợp cho người dùng, chẳng hạn như bằng cách cung cấp một nút "Thử lại" khidontAllow()
phản hồi bằngPolicy.RETRY
, điều này có thể là do dịch vụ không hoạt động. - Trong trường hợp xảy ra lỗi ứng dụng, chẳng hạn như khi ứng dụng cố gắng kiểm tra giấy phép của tên gói không hợp lệ,
LicenseChecker
sẽ chuyển phản hồi lỗi tới phương thứcapplicationError()
của LicenseCheckerCallback.
Xin lưu ý rằng ngoài việc bắt đầu kiểm tra giấy phép và xử lý kết quả, được mô tả trong phần bên dưới, ứng dụng còn cần cung cấp Quy trình triển khai chính sách, nếu Policy
lưu trữ dữ liệu phản hồi (ví dụ: ServerManagedPolicy) và cách triển khai Trình làm rối mã nguồn.
Thêm các lệnh nhập
Trước tiên, hãy mở tệp lớp Activity chính của ứng dụng và nhập LicenseChecker
và LicenseCheckerCallback
từ gói 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;
Nếu bạn đang dùng cách triển khai Policy
mặc định được cung cấp cùng với LVL, ServerManagedPolicy, hãy nhập tệp này cùng với AESObfuscator. Nếu bạn đang dùng Policy
hoặc Obfuscator
tuỳ chỉnh, hãy nhập các thông tin này.
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;
Triển khai LicenseCheckerCallback dưới dạng lớp bên trong riêng tư
LicenseCheckerCallback
là giao diện do LVL cung cấp để xử lý kết quả kiểm tra giấy phép. Để hỗ trợ cấp phép bằng LVL, bạn phải triển khai LicenseCheckerCallback
và các phương thức của nó để cho phép hoặc không cho phép truy cập vào ứng dụng.
Kết quả của việc kiểm tra giấy phép luôn là lệnh gọi đến một trong các phương thức LicenseCheckerCallback
, được thực hiện dựa trên xác thực tải trọng phản hồi, chính mã phản hồi máy chủ và bất kỳ quá trình xử lý bổ sung nào khác do Policy
cung cấp. Ứng dụng của bạn có thể triển khai các phương thức theo bất kỳ cách nào cần thiết. Nhìn chung, tốt nhất là bạn nên duy trì các phương thức đơn giản, giới hạn các phương thức đó trong việc quản lý trạng thái giao diện người dùng và quyền truy cập vào ứng dụng. Nếu bạn muốn thêm quy trình xử lý các phản hồi giấy phép, chẳng hạn như bằng cách liên hệ với một máy chủ phụ trợ hoặc áp dụng các ràng buộc tuỳ chỉnh, bạn nên cân nhắc việc kết hợp mã đó vào Policy
, thay vì nhập mã đó vào các phương thức LicenseCheckerCallback
.
Trong hầu hết trường hợp, bạn nên khai báo quá trình triển khai LicenseCheckerCallback
dưới dạng một lớp riêng tư bên trong lớp Activity chính của ứng dụng.
Triển khai các phương thức allow()
và dontAllow()
nếu cần. Để bắt đầu, bạn có thể dùng các hành vi xử lý kết quả đơn giản trong các phương thức, chẳng hạn như hiện kết quả cấp phép trong hộp thoại. Điều này giúp bạn chạy ứng dụng sớm hơn và có thể hỗ trợ gỡ lỗi. Sau khi đã xác định được các hành vi chính xác mà bạn mong muốn thì bạn có thể thêm cách xử lý phức tạp hơn.
Dưới đây là một số đề xuất để xử lý các phản hồi không được cấp phép trong dontAllow()
:
- Hiển thị hộp thoại "Thử lại" cho người dùng, kể cả nút để bắt đầu kiểm tra giấy phép mới nếu
reason
được cung cấp làPolicy.RETRY
. - Hiển thị hộp thoại "Mua ứng dụng này", bao gồm nút liên kết sâu người dùng đến trang chi tiết của ứng dụng trên Google Play, từ đó người dùng có thể mua ứng dụng. Để biết thêm thông tin về cách thiết lập các đường liên kết như vậy, hãy xem bài viết Liên kết với sản phẩm của bạn.
- Hiện thông báo Toast cho biết các tính năng của ứng dụng bị hạn chế vì chưa được cấp phép.
Ví dụ bên dưới cho thấy cách ứng dụng mẫu LVL triển khai LicenseCheckerCallback
với các phương thức hiện kết quả kiểm tra giấy phép trong hộp thoại.
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); } } }
Ngoài ra, bạn nên triển khai phương thức applicationError()
mà LVL gọi để cho phép ứng dụng xử lý các lỗi không thể thử lại. Để biết danh sách các lỗi như vậy, hãy xem Mã phản hồi của máy chủ trong Tài liệu tham khảo về hoạt động cấp phép. Bạn có thể triển khai phương thức này theo bất kỳ cách nào cần thiết. Trong hầu hết trường hợp, phương thức này sẽ ghi lại mã lỗi và gọi dontAllow()
.
Tạo Trình xử lý để đăng từ LicenseCheckerCallback lên luồng giao diện người dùng
Trong quá trình kiểm tra giấy phép, LVL chuyển yêu cầu đến ứng dụng Google Play, ứng dụng này sẽ xử lý thông tin giao tiếp với máy chủ cấp phép. LVL chuyển yêu cầu qua IPC không đồng bộ (dùng Binder
) để việc xử lý thực tế và giao tiếp qua mạng không diễn ra trên một luồng do ứng dụng của bạn quản lý. Tương tự, khi nhận được kết quả, ứng dụng Google Play sẽ gọi một phương thức gọi lại qua IPC. Phương thức này sẽ thực thi trong một nhóm luồng IPC trong quá trình xử lý ứng dụng.
Lớp LicenseChecker
quản lý giao tiếp IPC của ứng dụng với ứng dụng Google Play, bao gồm cả lệnh gọi gửi yêu cầu và lệnh gọi lại nhận phản hồi. LicenseChecker
cũng theo dõi các yêu cầu giấy phép mở và quản lý thời gian chờ của các yêu cầu này.
Để ứng dụng có thể xử lý thời gian chờ đúng cách đồng thời xử lý các phản hồi nhận được mà không ảnh hưởng đến chuỗi giao diện người dùng của ứng dụng, LicenseChecker
sẽ tạo một luồng trong nền khi tạo thực thể. Trong luồng, thực thể này thực hiện tất cả quy trình xử lý kết quả kiểm tra giấy phép, cho dù kết quả là phản hồi nhận được từ máy chủ hay lỗi hết thời gian chờ. Khi kết thúc quá trình xử lý, LVL gọi các phương thức LicenseCheckerCallback
từ luồng trong nền.
Đối với ứng dụng, điều này có nghĩa là:
- Trong nhiều trường hợp, hệ thống sẽ gọi các phương thức
LicenseCheckerCallback
từ một luồng trong nền. - Các phương thức đó sẽ không thể cập nhật trạng thái hoặc gọi bất kỳ quá trình nào trong luồng giao diện người dùng, trừ khi bạn tạo một Trình xử lý trong luồng giao diện người dùng và đăng các phương thức gọi lại của bạn đăng lên Trình xử lý.
Nếu bạn muốn các phương thức LicenseCheckerCallback
cập nhật luồng giao diện người dùng, hãy tạo thực thể Handler
trong phương thức onCreate()
của Activity chính, như minh hoạ bên dưới. Trong ví dụ này, các phương thức LicenseCheckerCallback
của ứng dụng mẫu LVL (xem ở trên) sẽ gọi displayResult()
để cập nhật chuỗi giao diện người dùng thông qua phương thức post()
của Trình xử lý.
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(); }
Sau đó, trong các phương thức LicenseCheckerCallback
, bạn có thể dùng các phương thức Trình xử lý để đăng các đối tượng Runnable hoặc Message lên Trình xử lý. Dưới đây là cách ứng dụng mẫu có trong bài viết LVL đăng Runnable lên một Trình xử lý trong luồng giao diện người dùng để hiện trạng thái giấy phép.
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); } }); }
Tạo thực thể LicenseChecker và LicenseCheckerCallback
Trong phương thức onCreate()
của Activity chính, hãy tạo các thực thể riêng tư của LicenseCheckerCallback và LicenseChecker
. Trước tiên, bạn phải tạo thực thể LicenseCheckerCallback
vì bạn cần chuyển tệp tham chiếu đến thực thể đó khi gọi hàm khởi tạo cho LicenseChecker
.
Khi tạo thực thể LicenseChecker
, bạn cần chuyển các tham số sau:
- Ứng dụng
Context
- Giá trị tham chiếu đến hoạt động triển khai
Policy
để sử dụng cho việc kiểm tra giấy phép. Trong hầu hết trường hợp, bạn sẽ dùng phương thức triển khaiPolicy
do LVL cung cấp, ServerManagedPolicy. - Biến Chuỗi giữ khoá công khai của tài khoản nhà xuất bản để cấp phép.
Nếu dùng ServerManagedPolicy, bạn sẽ không cần truy cập trực tiếp vào lớp, do đó, bạn có thể tạo thực thể của lớp này trong hàm khởi tạo LicenseChecker
như trong ví dụ sau. Xin lưu ý rằng bạn cần chuyển tệp tham chiếu đến một thực thể mới của Trình làm rối mã nguồn khi bạn tạo ServerManagedPolicy.
Ví dụ bên dưới cho biết cách tạo thực thể của LicenseChecker
và LicenseCheckerCallback
từ phương thức onCreate()
của một lớp Activity.
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. ); ... } }
Xin lưu ý rằng LicenseChecker
chỉ gọi các phương thức LicenseCheckerCallback
từ luồng giao diện người dùng nếu có phản hồi giấy phép hợp lệ được lưu vào bộ nhớ đệm cục bộ. Nếu yêu cầu kiểm tra giấy phép được gửi tới máy chủ, thì các lệnh gọi lại luôn xuất phát từ luồng trong nền, ngay cả đối với lỗi mạng.
Gọi CheckAccess() để bắt đầu kiểm tra giấy phép
Trong phần Activity chính của bạn, hãy thêm một lệnh gọi vào phương thức checkAccess()
của thực thể LicenseChecker
. Trong lệnh gọi, hãy truyền một tệp tham chiếu đến thực thể LicenseCheckerCallback
dưới dạng tham số. Nếu bạn cần xử lý bất kỳ hiệu ứng giao diện người dùng đặc biệt nào hoặc quản lý trạng thái trước lệnh gọi, thì bạn có thể thấy sự hữu ích khi gọi checkAccess()
từ phương thức trình bao bọc. Ví dụ: ứng dụng mẫu LVL gọi checkAccess()
từ phương thức trình bao bọc 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); }
Nhúng khoá công khai để cấp phép
Đối với mỗi ứng dụng, dịch vụ Google Play sẽ tự động tạo một cặp khoá công khai/riêng tư RSA 2048-bit dùng để cấp phép và thanh toán trong ứng dụng. Cặp khoá này được liên kết duy nhất với ứng dụng. Mặc dù liên kết với ứng dụng, cặp khoá này không giống với khoá bạn dùng để ký ứng dụng (hoặc bắt nguồn từ ứng dụng).
Google Play Console tiết lộ khoá công khai để cấp phép cho tất cả nhà phát triển đã đăng nhập vào Play Console, nhưng khoá riêng tư sẽ được ẩn ở một vị trí an toàn khỏi tất cả người dùng. Khi một ứng dụng yêu cầu kiểm tra giấy phép của ứng dụng được xuất bản trong tài khoản của bạn, máy chủ cấp phép sẽ ký phản hồi của giấy phép bằng cách sử dụng khoá riêng tư của cặp khoá trong ứng dụng. Khi LVL nhận được phản hồi, ứng dụng này sẽ dùng khoá công khai do ứng dụng cung cấp để xác minh chữ ký của phản hồi giấy phép.
Để thêm giấy phép vào ứng dụng, bạn phải lấy khoá công khai của ứng dụng để cấp phép và sao chép khoá đó vào ứng dụng. Dưới đây là cách tìm khoá công khai của ứng dụng để cấp phép:
- Truy cập vào Google Play Console rồi đăng nhập. Đảm bảo rằng bạn đăng nhập vào tài khoản mà tại đó ứng dụng bạn đang cấp phép được xuất bản (hoặc sẽ được xuất bản).
- Trong trang chi tiết về ứng dụng, hãy tìm đường liên kết Dịch vụ và API rồi nhấp vào đường liên kết đó.
- Trong trang Dịch vụ và API, hãy tìm phần Cấp phép và Thanh toán trong ứng dụng. Khoá công khai để cấp phép được cung cấp cho bạn trong trường Khoá cấp phép cho ứng dụng này.
Để thêm khoá công khai vào ứng dụng, bạn chỉ cần sao chép/dán chuỗi khoá từ trường đó vào ứng dụng dưới dạng giá trị của biến Chuỗi BASE64_PUBLIC_KEY
. Khi sao chép, hãy đảm bảo rằng bạn đã chọn toàn bộ chuỗi khoá mà không bỏ qua bất kỳ ký tự nào.
Dưới đây là ví dụ của ứng dụng mẫu 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 ... }
Gọi phương thức onDestroy () của LicenseChecker để đóng các kết nối IPC
Cuối cùng, để LVL dọn dẹp trước khi ứng dụng Context
thay đổi, hãy thêm một lệnh gọi vào phương thức onDestroy()
của LicenseChecker
trong quá trình triển khai onDestroy()
của Activity. Lệnh gọi này sẽ khiến LicenseChecker
đóng mọi kết nối IPC đang mở với Dịch vụ cấp phép của ứng dụng Google Play và xoá mọi tệp tham chiếu cục bộ đến dịch vụ và trình xử lý.
Việc không thể gọi phương thức onDestroy()
của LicenseChecker
có thể gây ra các sự cố trong vòng đời (lifecycle) của ứng dụng. Ví dụ: nếu người dùng thay đổi hướng của màn hình trong khi yêu cầu kiểm tra giấy phép đang hoạt động, thì ứng dụng Context
sẽ bị huỷ. Nếu ứng dụng không đóng đúng cách kết nối IPC của LicenseChecker
, thì ứng dụng của bạn sẽ gặp sự cố khi nhận được phản hồi. Tương tự, nếu người dùng thoát khỏi ứng dụng trong đang tiến hành kiểm tra giấy phép, thì ứng dụng sẽ gặp sự cố khi nhận được phản hồi, trừ khi ứng dụng đó đã gọi đúng phương thức onDestroy()
của LicenseChecker
để ngắt kết nối khỏi dịch vụ.
Dưới đây là ví dụ từ ứng dụng mẫu có trong LVL, trong đó mChecker
là thực thể LicenseChecker
:
Kotlin
override fun onDestroy() { super.onDestroy() checker.onDestroy() ... }
Java
@Override protected void onDestroy() { super.onDestroy(); checker.onDestroy(); ... }
Nếu bạn đang mở rộng hoặc sửa đổi LicenseChecker
, thì bạn cũng có thể cần phải gọi phương thức finishCheck()
của LicenseChecker
để xoá mọi kết nối IPC mở.
Triển khai DeviceLimiter
Trong một số trường hợp, bạn có thể muốn Policy
giới hạn số lượng thiết bị thực tế được phép dùng một giấy phép. Điều này sẽ ngăn người dùng di chuyển một ứng dụng được cấp phép sang một số thiết bị và dùng ứng dụng trên các thiết bị đó bằng cùng một mã tài khoản. Việc này cũng sẽ ngăn người dùng "chia sẻ" ứng dụng bằng cách cung cấp thông tin tài khoản liên kết với giấy phép đó cho các cá nhân khác. Sau đó, những cá nhân này có thể đăng nhập vào tài khoản đó trên thiết bị của họ và truy cập vào giấy phép ứng dụng.
LVL hỗ trợ việc cấp phép cho từng thiết bị bằng cách cung cấp một giao diện DeviceLimiter
. Giao diện này khai báo một phương thức duy nhất là allowDeviceAccess()
. Khi thực hiện phản hồi từ máy chủ cấp phép, LicenseValidator sẽ gọi allowDeviceAccess()
và truyền một chuỗi mã nhận dạng người dùng được trích xuất từ phản hồi.
Nếu bạn không muốn hỗ trợ giới hạn thiết bị, bạn không cần làm gì cả — lớp LicenseChecker
sẽ tự động dùng cách triển khai mặc định có tên là NullDevicelimiter. Như đã thể hiện trong tên gọi, NullDevice Limiter là một lớp "không hoạt động" có phương thức allowDeviceAccess()
chỉ trả về phản hồi LICENSED
cho tất cả người dùng và thiết bị.
Thận trọng: Bạn không nên dùng giấy phép cho mỗi thiết bị đối với hầu hết các ứng dụng vì:
- Phương thức này yêu cầu bạn cung cấp một máy chủ phụ trợ để quản lý người dùng và các mối liên kết của thiết bị, cũng như
- Điều này có thể vô tình dẫn đến việc người dùng bị từ chối truy cập vào một ứng dụng mà họ đã mua hợp pháp trên thiết bị khác.
Làm rối mã nguồn của bạn
Để đảm bảo tính bảo mật của ứng dụng, đặc biệt là đối với một ứng dụng trả phí sử dụng tính năng cấp phép và/hoặc biện pháp giới hạn và bảo vệ tuỳ chỉnh, điều rất quan trọng là cần làm rối mã nguồn xử lý ứng dụng của bạn. Việc làm rối mã nguồn đúng cách sẽ khiến người dùng gặp khó khăn hơn trong việc dịch ngược mã byte của ứng dụng, sửa đổi mã đó (chẳng hạn như xoá mã kiểm tra giấy phép), rồi biên dịch lại.
Một số chương trình làm rối mã nguồn có sẵn đối cho các ứng dụng Android, bao gồm ProGuard. Ứng dụng này cũng cung cấp các tính năng tối ưu hoá mã. Bạn nên dùng ProGuard hoặc chương trình tương tự để làm rối mã nguồn cho tất cả ứng dụng sử dụng Dịch vụ cấp phép của Google Play.
Xuất bản ứng dụng được cấp phép
Khi hoàn tất quá trình kiểm thử việc triển khai giấy phép, bạn có thể xuất bản ứng dụng trên Google Play. Làm theo các bước thông thường để chuẩn bị, ký, sau đó phát hành ứng dụng.
Nơi yêu cầu hỗ trợ
Nếu bạn có thắc mắc hoặc gặp vấn đề khi triển khai hoạt động xuất bản trong các ứng dụng của mình, vui lòng sử dụng tài nguyên hỗ trợ được liệt kê trong bảng dưới đây. Bằng cách chuyển truy vấn đến đúng diễn đàn, bạn có thể nhận được sự hỗ trợ cần thiết nhanh hơn.
Loại hỗ trợ | Tài nguyên | Phạm vi chủ đề |
---|---|---|
Các vấn đề về việc phát triển và kiểm thử | Google Groups: android-developers | Tải LVL xuống và tích hợp, dự án thư viện, câu hỏi về Policy , ý tưởng trải nghiệm người dùng, xử lý phản hồi, Obfuscator , IPC, thiết lập môi trường kiểm thử |
Stack Overflow: http://stackoverflow.com/questions/tagged/android | ||
Các vấn đề về tài khoản, phát hành và triển khai | Diễn đàn trợ giúp Google Play | Tài khoản của nhà xuất bản, cặp khoá cấp phép, tài khoản kiểm thử, phản hồi máy chủ, phản hồi kiểm thử, triển khai ứng dụng và kết quả |
Câu hỏi thường gặp về việc hỗ trợ gói Cấp phép của Google Market | ||
Công cụ theo dõi lỗi LVL | Công cụ theo dõi lỗi dự án Marketlicensing | Báo cáo lỗi và vấn đề liên quan cụ thể đến lớp mã nguồn LVL và quá trình triển khai giao diện |
Để biết thông tin chung về cách đăng bài lên các nhóm được liệt kê ở trên, hãy xem phần Tài nguyên cộng đồng trên trang Tài nguyên hỗ trợ dành cho nhà phát triển.
Tài nguyên khác
Ứng dụng mẫu đi kèm với LVL cung cấp một ví dụ đầy đủ về cách bắt đầu kiểm tra giấy phép và xử lý kết quả trong lớp MainActivity
.