Thêm API Tính toàn vẹn của Play vào ứng dụng Android

1. Giới thiệu

Lần cập nhật gần đây nhất: Ngày 4 tháng 1 năm 2023

API Tính toàn vẹn của Play là gì?

API Tính toàn vẹn của Play giúp bảo vệ các ứng dụng và trò chơi của bạn khỏi những tương tác tiềm ẩn rủi ro và lừa đảo. Bạn có thể dùng API Tính toàn vẹn của Play để thu thập kết quả về tính toàn vẹn của ứng dụng và thiết bị, từ đó phản hồi bằng những hành động thích hợp để giảm thiểu các cuộc tấn công và hành vi sai trái như lừa đảo, gian lận và truy cập trái phép.

Giải pháp trước đây

API Tính toàn vẹn của Play thay thế 2 giải pháp trước đây, đó là: Thư viện cấp phép ứng dụngAPI Chứng thực SafetyNet. Bạn nên sử dụng API Tính toàn vẹn của Play cho các ứng dụng mới. Bạn cần cân nhắc cập nhật để dùng API Tính toàn vẹn của Play cho các ứng dụng hiện có đang dùng những giải pháp trước đây.

Chọn một đường dẫn

API Tính toàn vẹn của Play bao gồm các lựa chọn về thư viện cho nhiều loại ứng dụng:

  • Trò chơi hoặc các ứng dụng khác được viết bằng C/C++
  • Ứng dụng được viết bằng ngôn ngữ lập trình Kotlin hoặc Java
  • Trò chơi được phát triển bằng công cụ Unity

Lớp học lập trình này cung cấp đường dẫn cho cả 3 lựa chọn. Bạn có thể chọn các đường dẫn có liên quan đến nhu cầu phát triển của mình. Lớp học lập trình này đề cập đến cả việc xây dựng và triển khai máy chủ phụ trợ. Máy chủ này được chia sẻ trên cả 3 loại ứng dụng.

Sản phẩm bạn sẽ tạo ra

Trong lớp học lập trình này, bạn sẽ tích hợp API Tính toàn vẹn của Play vào một ứng dụng mẫu và dùng API này để kiểm tra tính toàn vẹn của thiết bị cũng như ứng dụng. Bạn sẽ triển khai một ứng dụng máy chủ phụ trợ dùng để hỗ trợ quy trình kiểm tra tính toàn vẹn.

Kiến thức bạn sẽ học được

  • Cách tích hợp thư viện API Tính toàn vẹn của Play vào ứng dụng
  • Cách sử dụng API Tính toàn vẹn của Play để kiểm tra tính toàn vẹn
  • Cách xử lý kết quả về tính toàn vẹn bằng máy chủ một cách an toàn
  • Cách diễn giải kết quả về tính toàn vẹn

Lớp học lập trình này tập trung vào API Tính toàn vẹn của Play. Các khái niệm và khối mã không liên quan sẽ không được giải thích chi tiết và chỉ được cung cấp cho bạn để sao chép và dán.

Bạn cần có

  • Tài khoản Google dành cho nhà phát triển Android, có trạng thái đăng ký là đang hoạt động, quyền truy cập vào Play Console và quyền truy cập vào Google Cloud Console.
  • Đối với đường dẫn C++ hoặc Kotlin, bạn cần có Android Studio 2021.1.1 trở lên.
  • Đối với đường dẫn Unity, bạn cần có Unity LTS phiên bản 2020 trở lên.
  • Một thiết bị chạy Android được kết nối với máy tính của bạn và đã bật Tuỳ chọn cho nhà phát triển cũng như tính năng Gỡ lỗi qua USB.

Lớp học lập trình này có các đường liên kết đến tài nguyên về cách ký và tải bản dựng lên Play Console, nhưng giả định rằng bạn đã nắm rõ quy trình này.

2. Lấy mã

Các dự án của lớp học lập trình này có trong kho lưu trữ Git. Trong thư mục mẹ của kho lưu trữ có 4 thư mục:

  • Thư mục server chứa mã cho máy chủ mẫu mà bạn sẽ triển khai.
  • Thư mục cpp chứa một dự án Android Studio để thêm API Tính toàn vẹn của Play vào trò chơi hoặc ứng dụng C++.
  • Thư mục kotlin chứa một dự án Android Studio để thêm API Tính toàn vẹn của Play vào ứng dụng Android tiêu chuẩn.
  • Thư mục unity chứa một dự án được tạo bằng phiên bản LTS 2020 của công cụ Unity để thêm API Tính toàn vẹn của Play vào dự án Unity.

Mỗi thư mục mẫu của ứng dụng có 2 thư mục con:

  • Thư mục start có phiên bản của dự án mà chúng ta sẽ sửa đổi trong lớp học lập trình này.
  • Thư mục final có một phiên bản của dự án phù hợp với giao diện dự án sau khi bạn hoàn thành lớp học lập trình.

Sao chép kho lưu trữ

Từ dòng lệnh, hãy thay đổi thư mục bạn muốn chứa thư mục add-play-integrity-codelab gốc, rồi sao chép dự án từ GitHub bằng cú pháp sau:

git clone https://github.com/android/add-play-integrity-codelab.git

Thêm phần phụ thuộc (chỉ C++)

Nếu có ý định sử dụng đường dẫn C++, bạn cần khởi chạy các mô-đun con của kho lưu trữ để thiết lập thư viện Dear ImGui được sử dụng cho giao diện người dùng. Để thực hiện việc này, từ dòng lệnh, hãy làm như sau:

  1. Thay đổi thư mục đang hoạt động thành: add-play-integrity-codelab/cpp/start/third-party
  2. git submodule update --init

3. Tìm hiểu về các hàm máy khách và máy chủ

Một yếu tố quan trọng của mô hình bảo mật API Tính toàn vẹn của Play là việc di chuyển các hoạt động xác thực ra khỏi thiết bị và chuyển sang một máy chủ bảo mật mà bạn điều khiển. Khi thực hiện các thao tác này trên máy chủ, bạn sẽ tránh được các tình huống như thiết bị bị xâm nhập tìm cách triển khai cuộc tấn công phát lại hoặc can thiệp vào nội dung tin nhắn.

Máy chủ mẫu trong lớp học lập trình này được dùng làm ví dụ và để đơn giản hoá, máy chủ này không có nhiều tính năng được mong đợi trong môi trường phát hành chính thức. Danh sách các giá trị đã tạo của tính năng này chỉ được lưu trữ trong bộ nhớ và không được bộ nhớ sao lưu liên tục. Điểm cuối của máy chủ không được định cấu hình để yêu cầu xác thực.

Điểm cuối performCommand

Máy chủ cung cấp điểm cuối /performCommand được truy cập qua một yêu cầu HTTP POST. Nội dung yêu cầu dự kiến là một tải trọng JSON với các cặp khoá/giá trị sau:

{
   "commandString": "command-here",
   "tokenString": "token-here"
}

Điểm cuối /performCommand trả về một tải trọng JSON với các cặp khoá/giá trị sau:

{
   "commandSuccess": true/false,
   "diagnosticMessage": "summary text",
   "expressToken": "token-here"
}

Nội dung thực tế của tham số commandString không quan trọng. Máy chủ xác thực tính toàn vẹn của commandString khi sử dụng API Tính toàn vẹn của Play nhưng không dùng giá trị lệnh. Mọi phiên bản ứng dụng đều dùng giá trị "TRANSFER FROM alice TO bob CURRENCY gems QUANTITY 1000".

Giá trị của tham số tokenString phải là:

  • Mã thông báo do API Tính toàn vẹn của Play tạo
  • Mã thông báo nhanh được lệnh gọi thành công trước đó trả về cho /performCommand

Máy chủ sẽ giải mã và xác thực mã thông báo do API Tính toàn vẹn của Play cung cấp. Kết quả của quá trình giải mã là tải trọng JSON của các tín hiệu về tính toàn vẹn. Tuỳ vào giá trị của tín hiệu, máy chủ có thể chọn phê duyệt hoặc từ chối lệnh này. Nếu đã giải mã thành công mã thông báo, thì hệ thống sẽ trả về nội dung mô tả tóm tắt các tín hiệu trong diagnosticMessage. Thông thường, bạn sẽ không trả về thông tin này cho ứng dụng trong ứng dụng chính thức. Tuy nhiên, các ứng dụng của lớp học lập trình dùng thông tin này để hiện kết quả hoạt động của bạn mà không yêu cầu phải xem nhật ký máy chủ. Nếu xảy ra tình trạng lỗi trong khi xử lý mã thông báo, thì lỗi này sẽ được trả về trong diagnosticMessage.

Tạo số chỉ dùng một lần

Để tạo yêu cầu về API Tính toàn vẹn của Play, bạn phải tạo một số chỉ dùng một lần và liên kết số này với yêu cầu. Số chỉ dùng một lần dùng để giúp đảm bảo yêu cầu về tính toàn vẹn là duy nhất và chỉ được xử lý một lần. Số chỉ dùng một lần cũng dùng để xác minh nội dung thông báo liên quan đến yêu cầu về tính toàn vẹn chưa bị sửa đổi. Để biết thêm thông tin về số chỉ dùng một lần cho API Tính toàn vẹn của Play, hãy xem tài liệu này.

Trong lớp học lập trình này, số chỉ dùng một lần được tạo bằng cách kết hợp 2 giá trị:

  • Số ngẫu nhiên 128 bit do trình tạo số ngẫu nhiên được bảo mật bằng mật mã tạo
  • Hàm băm SHA-256 của giá trị commandString

API Tính toàn vẹn của Play dự kiến rằng số chỉ dùng một lần sẽ là một chuỗi Base64 không được đệm mã hoá bằng URL. Để tạo chuỗi số chỉ dùng một lần, lớp học lập trình này sẽ chuyển đổi các mảng byte của số ngẫu nhiên và giá trị băm thành các chuỗi hex rồi nối các chuỗi đó. Chuỗi kết quả là một chuỗi Base64 hợp lệ nhưng không được mã hoá hoặc giải mã như vậy.

Các ứng dụng của lớp học lập trình này truy xuất số ngẫu nhiên bằng cách gọi một điểm cuối /getRandom trên máy chủ bằng yêu cầu HTTP GET. Đây là phương thức an toàn nhất để tạo ngẫu nhiên, vì máy chủ có thể xác minh rằng đây là nguồn của số ngẫu nhiên dùng trong yêu cầu lệnh. Tuy nhiên, phương thức này sẽ tạo ra thêm một lượt trả về máy chủ. Ứng dụng có thể loại bỏ việc trả về này bằng cách tự tạo số ngẫu nhiên, ở một số điểm đánh đổi tính bảo mật.

Mã thông báo nhanh

Vì việc gọi PIA tiêu tốn nhiều tài nguyên, nên máy chủ cũng cung cấp mã thông báo nhanh, một phương pháp xác thực thay thế mang lại khả năng bảo mật thấp hơn với chi phí thấp hơn. Mã thông báo nhanh được trả về trong trường expressToken bằng lệnh gọi /serverCommand thành công với hoạt động kiểm tra tính toàn vẹn đã vượt qua. Việc gọi API Tính toàn vẹn của Play sẽ tiêu tốn tài nguyên tính toán nên được dùng để bảo vệ các hoạt động có giá trị cao. Bằng cách trả về mã thông báo nhanh, máy chủ sẽ cung cấp quá trình xác thực có khả năng bảo mật thấp hơn cho những hoạt động có thể ít quan trọng hoặc xảy ra quá thường xuyên và không cần xác thực toàn bộ bằng API Tính toàn vẹn của Play. Bạn có thể sử dụng mã thông báo nhanh thay cho mã thông báo API Tính toàn vẹn của Play khi gọi /serverCommand. Mỗi mã thông báo nhanh chỉ dùng được một lần. Các lệnh gọi /serverCommand thành công bằng mã thông báo nhanh hợp lệ sẽ trả về một mã thông báo nhanh mới.

Trong quá trình triển khai lớp học lập trình, vì mã thông báo nhanh được tạo riêng trên máy chủ nên các lệnh này vẫn được bảo vệ khỏi những cuộc tấn công phát lại. Tuy nhiên, mã thông báo nhanh kém an toàn hơn vì bỏ qua biện pháp bảo vệ bằng hàm băm khỏi lệnh sửa đổi và không thể phát hiện các hoạt động sửa đổi thiết bị xảy ra sau lệnh gọi ban đầu đến API Tính toàn vẹn của Play.

Cấu trúc máy chủ của lớp học lập trình

Trong lớp học lập trình này, bạn có thể tạo thực thể cho một máy chủ bằng cách sử dụng chương trình máy chủ mẫu đi kèm được viết bằng Kotlin thông qua khung Ktor. Dự án này có các tệp cấu hình để triển khai cho Google Cloud App Engine. Các hướng dẫn trong lớp học lập trình này đề cập đến việc xây dựng và triển khai cho App Engine. Nếu bạn sử dụng một nhà cung cấp dịch vụ đám mây khác, thì Ktor sẽ đưa ra hướng dẫn triển khai cho nhiều dịch vụ đám mây. Bạn có thể sửa đổi dự án cho phù hợp và triển khai dịch vụ mà mình muốn. Việc triển khai cho phiên bản máy chủ cục bộ của riêng bạn là một lựa chọn bổ sung.

Bạn không bắt buộc phải sử dụng mã mẫu cho máy chủ của mình. Nếu có một khung ứng dụng web ưu tiên, bạn có thể triển khai điểm cuối /getRandom/performCommand trong khung của riêng mình bằng cách sử dụng máy chủ mẫu của lớp học lập trình làm hướng dẫn.

Thiết kế ứng dụng

Cả 3 phiên bản ứng dụng, công cụ C++, Kotlin và Unity đều có giao diện người dùng tương tự nhau.

Nút Request random (Yêu cầu ngẫu nhiên) sẽ gọi điểm cuối /getRandom trên máy chủ. Kết quả sẽ xuất hiện trong trường văn bản. Bạn có thể dùng thông tin này để xác minh kết nối và chức năng của máy chủ trước khi thêm tính năng tích hợp API Tính toàn vẹn của Play.

Nút Call server with integrity check (Gọi máy chủ bằng hoạt động kiểm tra tính toàn vẹn) không có tác dụng gì khi bắt đầu lớp học lập trình. Bạn sẽ làm theo các bước để thêm mã cho các thao tác sau:

  • Gọi /getRandom để nhận một số ngẫu nhiên
  • Tạo một số chỉ dùng một lần
  • Tạo yêu cầu API Tính toàn vẹn của Play bằng số chỉ dùng một lần
  • Gọi /performCommand bằng mã thông báo do yêu cầu về API Tính toàn vẹn của Play tạo
  • Hiện kết quả của /performCommand

Kết quả của lệnh này hiện trong trường văn bản. Đối với một lệnh thành công, đây là bản tóm tắt thông tin kết quả của thiết bị trong hoạt động kiểm tra API Tính toàn vẹn của Play.

Nút Call server with express token (Gọi máy chủ bằng mã thông báo nhanh) xuất hiện sau thao tác Call server with integrity check (Gọi máy chủ bằng hoạt động kiểm tra tính toàn vẹn) thành công. Phương thức này gọi /performCommand bằng mã thông báo nhanh từ /performCommand trước đó. Một trường văn bản được dùng để hiện trạng thái thành công hoặc không thành công của lệnh. Giá trị của mã thông báo nhanh được trả về sẽ hiện trong trường văn bản dùng cho các số ngẫu nhiên.

Các hàm API Tính toàn vẹn của Play sẽ báo cáo lỗi bằng cách trả về một mã lỗi. Để biết thêm thông tin chi tiết về các mã lỗi này, hãy xem tài liệu về API Tính toàn vẹn của Play. Một số lỗi có thể do điều kiện môi trường gây ra, chẳng hạn như kết nối Internet không ổn định hoặc thiết bị quá tải. Đối với những lỗi như vậy, hãy cân nhắc thêm lựa chọn thử lại bằng thuật toán thời gian đợi luỹ thừa. Trong lớp học lập trình này, các lỗi về API Tính toàn vẹn của Play sẽ được in trong Logcat.

4. Thiết lập Google Cloud App Engine

Để sử dụng Google Cloud, hãy thực hiện các bước sau:

  1. Đăng ký Google Cloud Platform. Sử dụng chính Tài khoản Google đã đăng ký trên Play Console.
  2. Tạo tài khoản thanh toán.
  3. Cài đặt và khởi chạy Google Cloud SDK.

Sử dụng Google Cloud CLI mới cài đặt để chạy các lệnh sau:

  1. Cài đặt tiện ích App Engine cho Java: gcloud components install app-engine-java
  2. Tạo một dự án Cloud mới, thay thế $yourname trong lệnh sau bằng một số giá trị nhận dạng riêng biệt: gcloud projects create $yourprojectname --set-as-default
  3. Tạo một ứng dụng App Engine trong dự án Cloud: gcloud app create

5. Triển khai máy chủ

Đặt tên cho gói ứng dụng

Trong bước này, bạn sẽ thêm tên gói ứng dụng vào mã máy chủ. Trong trình chỉnh sửa văn bản, hãy mở tệp nguồn ValidateCommand.kt. Tệp này nằm trong thư mục sau:

add-play-integrity-codelab/server/src/main/kotlin/com/google/play/integrity/codelab/server/util

Tìm dòng sau và thay thế văn bản phần giữ chỗ bằng một mã nhận dạng gói duy nhất rồi lưu tệp:

const val APPLICATION_PACKAGE_IDENTIFIER = "com.your.app.package"

Sau đó, bạn sẽ đặt giá trị nhận dạng này trong dự án ứng dụng trước khi tải ứng dụng lên Play Console.

Xây dựng máy chủ và triển khai App Engine

Sử dụng Google Cloud CLI để chạy lệnh sau từ thư mục add-play-integrity/server nhằm xây dựng và triển khai máy chủ:

Trên Linux hoặc macOS:

./gradlew appengineDeploy

Trên Microsoft Windows:

gradlew.bat appengineDeploy

Ghi lại vị trí Dịch vụ đã triển khai trong dữ liệu đầu ra của quá trình triển khai thành công. Bạn sẽ cần URL này để định cấu hình ứng dụng nhằm giao tiếp với máy chủ.

Xác minh quá trình triển khai

Bạn có thể sử dụng Google Cloud CLI để chạy lệnh sau nhằm xác minh máy chủ đang hoạt động đúng cách:

gcloud app browse

Lệnh này sẽ mở ra một trình duyệt web và URL gốc. Máy chủ mẫu sẽ hiện thông báo Hello World! (Xin chào!) khi được truy cập từ URL gốc.

6. Định cấu hình ứng dụng trong Play Console

Định cấu hình tính toàn vẹn của ứng dụng trong Play Console

Nếu đã có mục nhập ứng dụng trong Play Console, thì bạn có thể sử dụng mục nhập đó cho lớp học lập trình này. Ngoài ra, hãy làm theo các bước tạo ứng dụng mới trong Play Console. Sau khi chọn hoặc tạo ứng dụng trong Play Console, bạn cần định cấu hình chỉ báo Tính toàn vẹn của ứng dụng. Trên trình đơn bên trái của Play Console, hãy chuyển đến phần Tính toàn vẹn của ứng dụng trong phần Bản phát hành.

Nhấp vào nút Liên kết dự án trên đám mây. Chọn dự án Google Cloud mà bạn đã sử dụng với máy chủ rồi nhấp vào nút Liên kết dự án.

Quyền truy cập của Google Cloud vào máy chủ của bạn

Máy chủ phụ trợ của bạn phải giải mã mã thông báo tính toàn vẹn do API Tính toàn vẹn của Play tạo trên ứng dụng. API Tính toàn vẹn của Play cung cấp 2 lựa chọn để quản lý khoá: Các khoá do Google tạo và quản lý hoặc khoá do nhà phát triển cung cấp. Lớp học lập trình này sử dụng hành vi mặc định được đề xuất của các khoá do Google quản lý.

Với khoá do Google quản lý, máy chủ phụ trợ của bạn sẽ chuyển mã thông báo về tính toàn vẹn đã mã hoá sang máy chủ Google Play để giải mã. Máy chủ lớp học lập trình này dùng Thư viện ứng dụng API của Google để giao tiếp với máy chủ Google Play.

Hiện tại, máy chủ đã được thiết lập và đang chạy, đồng thời bạn đã định cấu hình ứng dụng trong Play Console, nên bạn có thể bắt đầu tuỳ chỉnh (các) ứng dụng tương ứng với nền tảng mà bạn chọn. Tất cả các bước dùng cho một nền tảng nhất định sẽ được nhóm lại với nhau, vì vậy, bạn có thể bỏ qua hướng dẫn cho các nền tảng mà bạn không sử dụng.

7. Tạo và chạy ứng dụng (C++)

Chạy Android Studio. Trong cửa sổ Welcome to Android Studio (Chào mừng bạn đến với Android Studio), hãy nhấp vào nút Open (Mở) rồi mở dự án Android Studio tại add-play-integrity-codelab/cpp/start.

Cập nhật mã ứng dụng

Trước khi tải bản dựng lên Google Play, bạn cần thay đổi mã ứng dụng từ mã mặc định thành một mã duy nhất. Thực hiện các bước sau đây:

  1. Trên ngăn Project (Dự án) trong Android Studio, hãy tìm tệp build.gradle trong start/app rồi mở tệp đó.
  2. Tìm câu lệnh applicationId.
  3. Thay đổi com.google.play.integrity.codelab.cpp thành tên gói mà bạn đã chọn khi triển khai máy chủ rồi lưu tệp.
  4. Ở đầu tệp, một biểu ngữ sẽ xuất hiện để thông báo cho bạn rằng các tệp Gradle đã thay đổi. Nhấp vào Sync Now (Đồng bộ hoá ngay) để tải lại và đồng bộ hoá lại tệp.
  5. Trên ngăn Project (Dự án) trong Android Studio, hãy mở tệp AndroidManifest.xml trong start/app/src/main.
  6. Tìm câu lệnh package="com.example.google.codelab.playintegritycpp".
  7. Thay thế com.example.google.codelab.playintegritycpp bằng tên gói duy nhất rồi lưu tệp.
  8. Trên ngăn Project (Dự án) trong Android Studio, hãy mở tệp PlayIntegrityCodelabActivity trong start/app/src/main/java/com.example.google.codelab.playintegritycpp.
  9. Tìm câu lệnh package com.example.google.codelab.playintegritycpp.
  10. Thay thế com.example.google.codelab.playintegritycpp bằng tên gói duy nhất.
  11. Nhấp chuột phải vào tên gói mới rồi chọn Show Context Action (Hiện hành động theo ngữ cảnh).
  12. Chọn Move to (Di chuyển sang) (tên gói mới của bạn).
  13. Chọn nút Sync Now (Đồng bộ hoá ngay) ở đầu tệp (nếu có).

Cập nhật URL máy chủ

Bạn cần cập nhật dự án để trỏ đến vị trí URL mà bạn đã triển khai máy chủ.

  1. Trên ngăn Project (Dự án) trong Android Studio, hãy mở tệp server_urls.hpp trong start/app/src/main/cpp.
  2. Thêm URL gốc xuất hiện khi bạn triển khai máy chủ vào các định nghĩa GET_RANDOM_URLPERFORM_COMMAND_URL rồi lưu tệp.

Kết quả sẽ có dạng tương tự như sau:

constexpr char GET_RANDOM_URL[] = "https://your-play-integrity-server.uc.r.appspot.com/getRandom";
constexpr char PERFORM_COMMAND_URL[] = "https://your-play-integrity-server.uc.r.appspot.com/performCommand";

URL cụ thể sẽ khác nhau tuỳ theo tên dự án và khu vực Google Cloud mà bạn sử dụng để triển khai máy chủ.

Tạo và chạy

Kết nối với một thiết bị Android được định cấu hình để phát triển. Trong Android Studio, hãy tạo dự án và chạy dự án đó trên thiết bị được kết nối. Ứng dụng sẽ xuất hiện như sau:

429ccc112f78d454.png

Chạm vào nút Request random (Yêu cầu ngẫu nhiên) để thực thi mã gửi yêu cầu HTTP tới máy chủ của bạn nhằm yêu cầu một số ngẫu nhiên. Sau một khoảng thời gian chờ ngắn, bạn sẽ thấy số ngẫu nhiên đó trên màn hình:

62acee42ba1fa80.png

Nếu thông báo lỗi xuất hiện, thì dữ liệu đầu ra của ngăn Logcat có thể chứa nhiều thông tin chi tiết hơn.

Sau khi xác minh bạn đang kết nối với máy chủ bằng cách truy xuất thành công một giá trị ngẫu nhiên, bạn có thể bắt đầu tích hợp API Tính toàn vẹn của Play.

8. Thêm API Tính toàn vẹn của Play vào dự án (C++)

Tải SDK xuống

Bạn sẽ cần tải SDK Play Core xuống rồi giải nén. Thực hiện các bước sau đây:

  1. Vào trang SDK gốc của Play Core rồi tải xuống SDK Play Core được đóng gói trong tệp .zip.
  2. Giải nén tệp zip đó.
  3. Đảm bảo thư mục mới trích xuất có tên là play-core-native-sdk rồi sao chép hoặc di chuyển thư mục đó vào thư mục add-play-integrity-codelab/cpp/start.

Cập nhật build.gradle

Trong Android Studio, trên ngăn Project (Dự án), hãy mở tệp build.gradle ở cấp mô-đun trong thư mục start/app.

Thêm dòng sau bên dưới dòng apply plugin: 'com.android.application':

def playcoreDir = file("../play-core-native-sdk")

Xác định vị trí khối externalNativeBuild trong khối defaultConfig và thay đổi câu lệnh arguments bên trong khối cmake sao cho khớp với lệnh sau:

                arguments "-DANDROID_STL=c++_shared",
                          "-DPLAYCORE_LOCATION=$playcoreDir"

Thêm đoạn mã sau vào khối android ở cuối:

    buildTypes {
        release {
            proguardFiles getDefaultProguardFile("proguard-android.txt"),
                          "proguard-rules.pro",
                          "$playcoreDir/proguard/common.pgcfg",
                          "$playcoreDir/proguard/integrity.pgcfg"
        }
    }

Thêm dòng này vào khối dependencies ở cuối:

    implementation files("$playcoreDir/playcore.aar")

Lưu các thay đổi. Ở đầu tệp, một biểu ngữ sẽ xuất hiện để thông báo cho bạn rằng các tệp Gradle đã thay đổi. Nhấp vào Sync Now (Đồng bộ hoá ngay) để tải lại và đồng bộ hoá lại tệp.

Cập nhật CMakeList.txt

Trong Android Studio, trên ngăn Project (Dự án), hãy mở tệp CMakeLists.txt trong thư mục start/app/src/main/cpp.

Thêm các dòng sau bên dưới các lệnh find_package:

include("${PLAYCORE_LOCATION}/playcore.cmake")
add_playcore_static_library()

Tìm dòng target_include_directories(game PRIVATE rồi thêm dòng sau bên dưới:

        ${PLAYCORE_LOCATION}/include

Tìm dòng target_link_libraries(game rồi thêm dòng sau bên dưới:

        playcore

Lưu tệp. Ở đầu tệp, một biểu ngữ sẽ xuất hiện để thông báo cho bạn rằng các tệp bản dựng bên ngoài đã thay đổi. Nhấp vào Sync Now (Đồng bộ hoá ngay) để tải lại và đồng bộ hoá lại tệp.

Chọn Make Project (Tạo dự án) trên trình đơn Build (Tạo) và xác minh dự án được tạo thành công.

9. Tạo yêu cầu về tính toàn vẹn (C++)

Ứng dụng của bạn thu thập thông tin về tính toàn vẹn bằng cách sử dụng API Tính toàn vẹn của Play để yêu cầu một mã thông báo. Sau đó, mã này sẽ được gửi đến máy chủ của bạn để giải mã và xác minh. Bây giờ, bạn sẽ thêm mã vào dự án để khởi chạy API Tính toàn vẹn của Play và dùng API này để tạo yêu cầu về tính toàn vẹn.

Thêm nút lệnh

Trong ứng dụng hoặc trò chơi thực tế, bạn có thể kiểm tra tính toàn vẹn trước khi thực hiện các hoạt động cụ thể, chẳng hạn như mua hàng tại cửa hàng hoặc tham gia chơi trò chơi có nhiều người chơi. Trong lớp học lập trình này, chúng ta sẽ thêm một nút vào giao diện người dùng để kích hoạt tính năng kiểm tra tính toàn vẹn theo cách thủ công và gọi máy chủ, truyền mã thông báo do API Tính toàn vẹn của Play tạo.

Dự án lớp học lập trình này chứa một lớp ClientManager, được xác định trong các tệp nguồn client_manager.cppclient_manager.hpp. Để thuận tiện, tệp này đã được thêm vào dự án nhưng thiếu mã triển khai mà giờ đây bạn sẽ thêm.

Để thêm nút giao diện người dùng, hãy bắt đầu bằng cách mở tệp demo_scene.cpp trong ngăn Project (Dự án) của Android Studio, trong thư mục start/app/src/main/cpp. Trước tiên, hãy tìm hàm DemoScene::GenerateCommandIntegrity() trống và thêm mã sau:

    const auto commandResult =
            NativeEngine::GetInstance()->GetClientManager()->GetOperationResult();
    if (commandResult != ClientManager::SERVER_OPERATION_PENDING) {
        if (ImGui::Button("Call server with integrity check")) {
            DoCommandIntegrity();
        }
    }

Tiếp theo, hãy tìm hàm DemoScene::DoCommandIntegrity() trống. Thêm mã sau:

    ClientManager *clientManager = NativeEngine::GetInstance()->GetClientManager();
    clientManager->StartCommandIntegrity();
    mServerRandom = clientManager->GetCurrentRandomString();

Lưu tệp. Bây giờ, bạn sẽ cập nhật lớp ClientManager của mẫu để thêm chức năng thực tế cho API Tính toàn vẹn của Play.

Cập nhật tệp tiêu đề cho trình quản lý

Mở tệp client_manager.hpp trong ngăn Project (Dự án) của Android Studio, trong thư mục start/app/src/main/cpp.

Thêm tệp tiêu đề cho API Tính toàn vẹn của Play bằng cách thêm dòng sau vào bên dưới dòng #include "util.hpp":

#include "play/integrity.h"

Lớp ClientManager cần lưu giữ thông tin tham chiếu đến các đối tượng IntegrityTokenRequestIntegrityTokenResponse. Thêm các dòng sau vào cuối phần định nghĩa lớp ClientManager:

    IntegrityTokenRequest *mTokenRequest;
    IntegrityTokenResponse *mTokenResponse;

Lưu tệp.

Khởi động và tắt API Tính toàn vẹn của Play

Trên ngăn Project (Dự án) của Android Studio, hãy mở tệp client_manager.cpp trong thư mục start/app/src/main/cpp.

Tìm hàm khởi tạo ClientManager::ClientManager(). Thay thế câu lệnh mInitialized = false; bằng mã sau:

    mTokenRequest = nullptr;
    mTokenResponse = nullptr;

    const android_app *app = NativeEngine::GetInstance()->GetAndroidApp();
    const IntegrityErrorCode errorCode = IntegrityManager_init(app->activity->vm,
                                                               app->activity->javaGameActivity);
    if (errorCode == INTEGRITY_NO_ERROR) {
        mInitialized = true;
    } else {
        mInitialized = false;
        ALOGE("Play Integrity initialization failed with error: %d", errorCode);
        ALOGE("Fatal Error: Play Integrity is unavailable and cannot be used.");
    }

Thêm mã sau vào hàm khởi tạo ClientManager::~ClientManager():

    if (mInitialized) {
        IntegrityManager_destroy();
        mInitialized = false;
    }

Yêu cầu mã thông báo tính toàn vẹn

Yêu cầu mã thông báo tính toàn vẹn từ API Tính toàn vẹn của Play là một hoạt động không đồng bộ. Bạn sẽ cần tạo một đối tượng yêu cầu mã thông báo, gán giá trị số chỉ dùng một lần và tạo yêu cầu mã thông báo. Để làm việc này, hãy thêm mã sau vào hàm ClientManager::StartCommandIntegrity() trống:

    // Only one request can be in-flight at a time
    if (mStatus != CLIENT_MANAGER_REQUEST_TOKEN) {
        mResult = SERVER_OPERATION_PENDING;
        // Request a fresh random
        RequestRandom();
        if (mValidRandom) {
            GenerateNonce();
            IntegrityTokenRequest_create(&mTokenRequest);
            IntegrityTokenRequest_setNonce(mTokenRequest, mCurrentNonce.c_str());

            const IntegrityErrorCode errorCode =
                    IntegrityManager_requestIntegrityToken(mTokenRequest, &mTokenResponse);
            if (errorCode != INTEGRITY_NO_ERROR) {
                // Log the error, in a real application, for potentially
                // transient errors such as network connectivity, you should
                // add retry with an exponential backoff
                ALOGE("Play Integrity returned error: %d", errorCode);
                CleanupRequest();
                mStatus = CLIENT_MANAGER_IDLE;
            } else {
                mStatus = CLIENT_MANAGER_REQUEST_TOKEN;
            }
        }
    }

Vì yêu cầu mã thông báo hoạt động không đồng bộ, bạn sẽ cần kiểm tra xem yêu cầu này đã hoàn tất hay chưa. Lớp ClientManager có một hàm Update() được gọi trong vòng lặp của bản cập nhật ứng dụng. Thêm mã sau vào hàm ClientManager::Update() để kiểm tra trạng thái của yêu cầu mã thông báo rồi xử lý kết quả sau khi hoàn tất:

    if (mStatus == CLIENT_MANAGER_REQUEST_TOKEN) {
        IntegrityResponseStatus responseStatus = INTEGRITY_RESPONSE_UNKNOWN;
        const IntegrityErrorCode errorCode =
                IntegrityTokenResponse_getStatus(mTokenResponse, &responseStatus);
        if (errorCode != INTEGRITY_NO_ERROR) {
            // Log the error, in a real application, for potentially
            // transient errors such as network connectivity, you should
            // add retry with an exponential backoff
            ALOGE("Play Integrity returned error: %d", errorCode);
            CleanupRequest();
            mStatus = CLIENT_MANAGER_IDLE;
        } else if (responseStatus == INTEGRITY_RESPONSE_COMPLETED) {
            std::string tokenString = IntegrityTokenResponse_getToken(mTokenResponse);
            SendCommandToServer(tokenString);
            CleanupRequest();
            mStatus = CLIENT_MANAGER_RESPONSE_AVAILABLE;
        }
    }

Xoá đối tượng yêu cầu

Bạn cần thông báo cho API Tính toàn vẹn của Play khi hoàn tất với các đối tượng phản hồi và yêu cầu mã thông báo để API có thể huỷ bỏ chúng cũng như xác nhận lại các tài nguyên. Thêm mã sau vào hàm ClientManager::CleanupRequest():

    if (mTokenResponse != nullptr) {
        IntegrityTokenResponse_destroy(mTokenResponse);
        mTokenResponse = nullptr;
    }
    if (mTokenRequest != nullptr) {
        IntegrityTokenRequest_destroy(mTokenRequest);
        mTokenRequest = nullptr;
    }

Chọn Make Project (Tạo dự án) trên trình đơn Build (Tạo) và xác minh dự án được tạo thành công.

10. Gửi mã thông báo đến máy chủ (C++)

Bây giờ, bạn sẽ thêm mã để gửi một lệnh đến máy chủ của mình, trong đó có mã thông báo tính toàn vẹn. Bạn cũng sẽ thêm mã để xử lý kết quả.

Thêm mã sau vào hàm ClientManager::SendCommandToServer():

// Note that for simplicity, we are doing HTTP operations as
// synchronous blocking instead of managing them from a
// separate network thread
HTTPClient client;
std::string errorString;

// Manually construct the json payload for ServerCommand
std::string payloadString = COMMAND_JSON_PREFIX;
payloadString += TEST_COMMAND;
payloadString += COMMAND_JSON_TOKEN;
payloadString += token;
payloadString += COMMAND_JSON_SUFFIX;

auto result = client.Post(PERFORM_COMMAND_URL, payloadString, &errorString);
if (!result) {
   ALOGE("SendCommandToServer Curl reported error: %s", errorString.c_str());
   mResult = SERVER_OPERATION_NETWORK_ERROR;
} else {
   ALOGI("SendCommandToServer result: %s", (*result).c_str())
   // Preset to success, ParseResult will set a failure result if the parsing
   // errors.
   mResult = SERVER_OPERATION_SUCCESS;
   ParseResult(*result);
}

Thêm mã sau vào hàm ClientManager::ParseResult():

    bool validJson = false;
    JsonLookup jsonLookup;
    if (jsonLookup.ParseJson(resultJson)) {
        // Look for all of our needed fields in the returned json
        auto commandSuccess = jsonLookup.GetBoolValueForKey(COMMANDSUCCESS_KEY);
        if (commandSuccess) {
            auto diagnosticString = jsonLookup.GetStringValueForKey(DIAGNOSTICMESSAGE_KEY);
            if (diagnosticString) {
                auto expressString = jsonLookup.GetStringValueForKey(EXPRESSTOKEN_KEY);
                if (expressString) {
                    if (*commandSuccess) {
                        // Express token only valid if the server reports the command succeeded
                        mValidExpressToken = true;
                    } else {
                        mValidExpressToken = false;
                        mResult = SERVER_OPERATION_REJECTED_VERDICT;
                    }
                    mCurrentSummary = *diagnosticString;
                    mCurrentExpressToken = *expressString;
                    validJson = true;
                }
            }
        }
    }
    if (!validJson) {
        mResult = SERVER_OPERATION_INVALID_RESULT;
    }

Bây giờ, bạn sẽ tạo một gói ứng dụng có chữ ký và tải gói ứng dụng đó lên Play Console để kiểm thử ứng dụng.

11. Tạo và tải lên (C++)

Tạo và thiết lập kho khoá cho ứng dụng

Android yêu cầu tất cả các ứng dụng phải có chữ ký số cùng một chứng chỉ trước khi được cài đặt hoặc cập nhật trên một thiết bị.

Chúng ta sẽ tạo một Kho khoá cho ứng dụng trong lớp học lập trình này. Nếu bạn đang xuất bản bản cập nhật cho trò chơi hiện có, hãy sử dụng cùng một Kho khoá như khi bạn phát hành các phiên bản ứng dụng trước đó.

Tạo kho khoá và Gói ứng dụng cho bản phát hành

Làm theo các bước tại Kho khoá với Android Studio để tạo một kho khoá rồi sử dụng kho khoá này để tạo một bản phát hành có chữ ký của trò chơi. Trong Android Studio, hãy chọn Generate Signed Bundle/APK (Tạo gói/APK có chữ ký) trên trình đơn Build (Tạo) để bắt đầu quy trình xây dựng. Chọn lựa chọn App Bundle khi được nhắc chọn Android App Bundle hoặc APK. Khi kết thúc quy trình này, bạn sẽ có một tệp .aab phù hợp để tải lên Google Play Console.

Tải lên Play Console

Sau khi tạo một tệp Gói ứng dụng, hãy tải tệp đó lên Play Console. Bạn nên sử dụng kênh kiểm thử nội bộ để nhanh chóng truy cập vào bản dựng.

Chạy bản thử nghiệm

Bây giờ, bạn nên tải xuống và chạy bản thử nghiệm từ Cửa hàng Play. Hiện tại, một mã thành công của phần giữ chỗ trong hàm sẽ gửi mã thông báo tính toàn vẹn tới máy chủ của bạn. Vì vậy, hoạt động kiểm tra tính toàn vẹn sẽ bắt đầu thành công và kết quả sẽ hiện như sau:

ef5f55d73f808791.png

Xin chúc mừng! Bạn đã tích hợp API Tính toàn vẹn của Play vào ứng dụng C++! Tiếp tục với các ví dụ khác về ứng dụng hoặc chuyển đến cuối lớp học lập trình này.

12. Tạo và chạy ứng dụng (Unity)

Dự án Unity của lớp học lập trình được tạo bằng Unity LTS 2020 (2020.3.31f1), nhưng sẽ tương thích với các phiên bản Unity cao hơn. Trình bổ trợ API Tính toàn vẹn của Play dành cho Unity tương thích với Unity LTS 2018 trở lên.

Thiết lập dự án

Thực hiện các bước sau đây:

  1. Trên Unity Hub hoặc Trình chỉnh sửa Unity, mở dự án Unity nằm trong add-play-integrity-codelab/unity/start.
  2. Sau khi dự án tải xong, chọn Build Settings... (Cài đặt bản dựng) trên trình đơn File (Tệp) của Unity.
  3. Trong cửa sổ Build Settings (Cài đặt bản dựng), thay đổi nền tảng thành Android.
  4. Trong cửa sổ Build Settings (Cài đặt bản dựng), nhấp vào nút Player Settings... (Cài đặt trình phát).
  5. Trong cửa sổ Project Settings (Cài đặt dự án), chọn danh mục Player (Trình phát), tìm phần Settings for Android (Chế độ cài đặt cho Android). Mở rộng danh sách Other Settings (Chế độ cài đặt khác).

b994587b808c7be4.png

  1. Tìm mục nhập Package Name (Tên gói) trong phần Identification (Nhận dạng).

d036e5be73096083.png

  1. Thay đổi tên gói thành mã nhận dạng bạn đã chọn khi triển khai máy chủ.
  2. Đóng cửa sổ Project Settings (Cài đặt dự án).
  3. Chọn Save Project (Lưu dự án) trên trình đơn File (Tệp) của Unity.

Cập nhật URL máy chủ

Bạn cần cập nhật dự án để trỏ đến vị trí URL mà bạn đã triển khai máy chủ. Để cập nhật, hãy thực hiện các bước sau:

  1. Mở tệp PlayIntegrityController.cs của thư mục Scripts trong IDE hoặc trình chỉnh sửa văn bản.
  2. Thay đổi giá trị của các biến URL_GETRANDOMURL_PERFORMCOMMAND để trỏ đến máy chủ của bạn.
  3. Lưu tệp.

Kết quả sẽ có dạng tương tự như sau:

    private readonly string URL_GETRANDOM = "https://your-play-integrity-server.uc.r.appspot.com/getRandom";
    private readonly string URL_PERFORMCOMMAND = "https://your-play-integrity-server.uc.r.appspot.com/performCommand";

URL cụ thể sẽ khác nhau tuỳ theo tên dự án và khu vực Google Cloud mà bạn sử dụng để triển khai máy chủ.

Kiểm thử chức năng của máy chủ

Bạn có thể kiểm thử chức năng của máy chủ bằng cách chạy dự án trong trình chỉnh sửa Unity. Thực hiện các bước sau đây:

  1. Mở tệp màn hình SampleScene nằm trong thư mục Scenes.
  2. Nhấp vào nút Play (Phát) trong trình chỉnh sửa.
  3. Nhấp vào nút Request random (Yêu cầu ngẫu nhiên) trong màn hình Game (Trò chơi).

Sau một khoảng thời gian trễ ngắn, giá trị ngẫu nhiên sẽ hiện trên màn hình, tương tự như sau:

f22c56cdd2e56050.png

13. Thêm trình bổ trợ API Tính toàn vẹn của Play vào dự án (Unity)

Tải trình bổ trợ xuống

Trong trình duyệt web, hãy mở trang bản phát hành cho kho lưu trữ Play Unity Plugins GitHub. Sử dụng phiên bản trình bổ trợ mới nhất. Tải com.google.play.integrity-<version> xuống.Tệp unitypackage giúp đảm bảo API Tính toàn vẹn của Play trong danh sách Assets (Tài sản).

Cài đặt trình bổ trợ

Trong thanh trình đơn của trình chỉnh sửa Unity, hãy chọn Assets -> Import Package -> Custom Package... (Tài sản -> Nhập gói -> Tuỳ chỉnh gói) rồi mở tệp .unitypackage mà bạn đã tải xuống. Nhấp vào nút Import (Nhập) sau khi cửa sổ Import Unity Package (Nhập gói Unity) xuất hiện.

Trình bổ trợ này bao gồm Trình quản lý phần phụ thuộc bên ngoài dành cho Unity (EDM4U). EDM4U triển khai độ phân giải phụ thuộc tự động cho các thành phần Java cần thiết để sử dụng API Tính toàn vẹn của Play. Khi bạn được nhắc bật giải pháp phụ thuộc tự động, hãy nhấp vào nút Enable (Bật).

5bf0be9139fab036.png

Bạn nên sử dụng độ phân giải tự động. Các vấn đề về phần phụ thuộc có thể khiến dự án của bạn không tạo hoặc chạy được.

14. Tạo yêu cầu về tính toàn vẹn (Unity)

Tạo yêu cầu về tính toàn vẹn

Để tạo yêu cầu về tính toàn vẹn, hãy thực hiện các bước sau.

  1. Mở tệp PlayIntegrityController.cs của thư mục Scripts trong IDE hoặc trình chỉnh sửa văn bản.
  2. Thêm dòng sau vào khối các câu lệnh using ở đầu tệp:
using Google.Play.Integrity;
  1. Tìm hàm RunIntegrityCommand() rồi thay thế câu lệnh yield return null; bằng mã sau:
        // Call our server to retrieve a random number.
        yield return GetRandomRequest();
        if (!string.IsNullOrEmpty(_randomString))
        {
            // Create an instance of an integrity manager.
            var integrityManager = new IntegrityManager();

            // Request the integrity token by providing a nonce.
            var tokenRequest = new IntegrityTokenRequest(GenerateNonceString(_randomString,
                TEST_COMMAND));
            var requestIntegrityTokenOperation =
                integrityManager.RequestIntegrityToken(tokenRequest);

            // Wait for PlayAsyncOperation to complete.
            yield return requestIntegrityTokenOperation;

            // Check the resulting error code.
            if (requestIntegrityTokenOperation.Error != IntegrityErrorCode.NoError)
            {
                // Log the error, in a real application, for potentially
                // transient errors such as network connectivity, you should
                // add retry with an exponential backoff
                Debug.Log($@"IntegrityAsyncOperation failed with error: 
                    {requestIntegrityTokenOperation.Error.ToString()}");
                yield break;
            }

            // Get the response.
            var tokenResponse = requestIntegrityTokenOperation.GetResult();

            // Send the command to our server with a POST request, including the
            // token, which will be decrypted and verified on the server.
            yield return PostServerCommand(tokenResponse.Token);
        }

Gửi lệnh đến máy chủ

Tiếp tục chỉnh sửa tệp PlayIntegrityController.cs bằng cách tìm hàm PostServerCommand() và thay thế câu lệnh yield return null; bằng mã sau:

        // Start a HTTP POST request to the performCommand URL, sending it the
        // command and integrity token data provided by Play Integrity.
        var serverCommand = new ServerCommand(TEST_COMMAND, tokenResponse);
        var commandRequest = new UnityWebRequest(URL_PERFORMCOMMAND, "POST");
        string commandJson = JsonUtility.ToJson(serverCommand);
        byte[] jsonBuffer = Encoding.UTF8.GetBytes(commandJson);
        commandRequest.uploadHandler = new UploadHandlerRaw(jsonBuffer);
        commandRequest.downloadHandler = new DownloadHandlerBuffer();
        commandRequest.SetRequestHeader(CONTENT_TYPE, JSON_CONTENT);
        yield return commandRequest.SendWebRequest();

        if (commandRequest.result == UnityWebRequest.Result.Success)
        {
            // Parse the command result Json
            var commandResult = JsonUtility.FromJson<CommandResult>(
                commandRequest.downloadHandler.text);
            if (commandResult != null)
            {
                resultLabel.text = commandResult.diagnosticMessage;
                _expressToken = commandResult.expressToken;
                if (commandResult.commandSuccess)
                {
                    resultLabel.color = Color.green;
                    expressButton.SetActive(true);
                }
                else
                {
                    resultLabel.color = Color.black;
                    expressButton.SetActive(false);
                }
            }
            else
            {
                Debug.Log("Invalid CommandResult json");
            }
        }
        else
        {
            Debug.Log($"Web request error on processToken: {commandRequest.error}");
        }

Lưu tệp.

15. Tạo và tải lên (Unity)

Sử dụng Trình quản lý kho khoá Android của trình chỉnh sửa Unity để định cấu hình bản dựng cần ký khi tải lên Play Console.

Sau khi định cấu hình thông tin ký, hãy thực hiện các bước sau:

  1. Chọn Build -> Build Settings... (Bản dựng -> Cài đặt bản dựng) trên trình đơn File (Tệp) của Unity.
  2. Đảm bảo SampleScene có trong danh sách Scenes in Build (Màn hình trong bản dựng).
  3. Đảm bảo bạn đã chọn hộp Build App Bundle (Google Play).
  4. Nhấp vào nút Build (Tạo) rồi đặt tên cho tệp xuất.

Sau khi tạo một tệp Gói ứng dụng, hãy tải tệp đó lên Play Console. Bạn nên sử dụng kênh kiểm thử nội bộ để nhanh chóng truy cập vào bản dựng.

Giờ đây, bạn có thể tải xuống và cài đặt bản dựng để chạy quy trình kiểm tra tính toàn vẹn. Kết quả sẽ có dạng tương tự như sau:

fa83cdb1a700ca0b.png

Xin chúc mừng! Bạn đã tích hợp API Tính toàn vẹn của Play vào dự án công cụ Unity! Tiếp tục với các ví dụ khác về ứng dụng hoặc chuyển đến cuối lớp học lập trình này.

16. Tạo và chạy dự án (Kotlin)

Chạy Android Studio. Trong cửa sổ Welcome to Android Studio (Chào mừng bạn đến với Android Studio), hãy nhấp vào nút Open (Mở) rồi mở dự án Android Studio tại add-play-integrity-codelab/kotlin/start.

Cập nhật mã ứng dụng

Trước khi tải bản dựng lên Google Play, bạn cần thay đổi mã ứng dụng từ mã mặc định thành một mã duy nhất. Thực hiện các bước sau đây:

  1. Trên ngăn Project (Dự án) trong Android Studio, hãy mở tệp build.gradle cho mô-đun PlayIntegrityCodelab.app.
  2. Tìm câu lệnh applicationId.
  3. Thay đổi com.example.google.codelab.playintegritykotlin thành giá trị nhận dạng mà bạn đã chọn khi triển khai máy chủ và lưu tệp.
  4. Ở đầu tệp, một biểu ngữ sẽ xuất hiện để thông báo cho bạn rằng các tệp Gradle đã thay đổi. Nhấp vào Sync Now (Đồng bộ hoá ngay) để tải lại và đồng bộ hoá lại tệp.

Cập nhật URL máy chủ

Bạn cần cập nhật dự án để trỏ đến vị trí URL mà bạn đã triển khai máy chủ. Để cập nhật, hãy thực hiện các bước sau:

  1. Trên ngăn Project (Dự án) trong Android Studio, hãy mở tệp IntegrityServer trong start/app/src/main/java/com.example.google.codelab.playintegritykotlin/integrity.
  2. Thay đổi URL từ ‘https://your.play-integrity.server.com' thành URL cơ sở của máy chủ rồi lưu tệp.

Kết quả sẽ có dạng tương tự như sau:

    private val SERVER_URL: String = "https://your-play-integrity-server.uc.r.appspot.com"

URL cụ thể sẽ khác nhau tuỳ theo tên dự án và khu vực Google Cloud mà bạn sử dụng để triển khai máy chủ.

Tạo và chạy

Kết nối với một thiết bị Android được định cấu hình để phát triển. Trong Android Studio, hãy tạo dự án và chạy dự án đó trên thiết bị được kết nối. Ứng dụng sẽ xuất hiện như sau:

d77ca71dc209452f.png

Khi khởi động, ứng dụng sẽ gọi điểm cuối getRandom trên máy chủ và hiện kết quả. Nếu xảy ra lỗi, chẳng hạn như URL không chính xác hoặc máy chủ không hoạt động, thì hộp thoại lỗi sẽ xuất hiện. Bạn có thể chọn nút Request Random (Yêu cầu ngẫu nhiên) để truy xuất một số ngẫu nhiên mới từ máy chủ. Nút Call server with integrity check (Gọi máy chủ bằng tính năng kiểm tra tính toàn vẹn) vẫn chưa có tác dụng. Bạn sẽ thêm chức năng đó vào các phần sau.

17. Thêm API Tính toàn vẹn của Play vào dự án (Kotlin)

Để thêm thư viện API Tính toàn vẹn của Play và các phần phụ thuộc hỗ trợ vào dự án, hãy thực hiện các bước sau:

  1. Trên ngăn Project (Dự án) trong Android Studio, hãy mở tệp build.gradle trong start/app.
  2. Tìm khối dependencies ở cuối tệp.
  3. Thêm các dòng sau vào cuối khối dependencies:
    implementation "com.google.android.play:integrity:1.0.1"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.1"
  1. Lưu tệp.
  2. Ở đầu tệp, một biểu ngữ sẽ xuất hiện để thông báo cho bạn rằng các tệp Gradle đã thay đổi. Nhấp vào Sync Now (Đồng bộ hoá ngay) để tải lại và đồng bộ hoá lại tệp.

Mẫu Kotlin sử dụng các coroutine. Thư viện kotlinx-coroutines-play-services thêm các tiện ích hỗ trợ thao tác với các đối tượng Task không đồng bộ trong API Tính toàn vẹn của Play từ bên trong coroutine Kotlin.

18. Tạo yêu cầu về tính toàn vẹn (Kotlin)

Trên ngăn Project (Dự án) trong Android Studio, hãy mở tệp IntegrityServer trong start/app/src/main/java/com.example.google.codelab.playintegritykotlin/integrity. Ở cuối tệp là một hàm integrityCommand trống. Giao diện người dùng sẽ gọi hàm này khi bạn nhấn nút Call server with integrity check (Gọi máy chủ bằng tính năng kiểm tra tính toàn vẹn).

Bạn sẽ thêm mã vào hàm integrityCommand để thực hiện các thao tác sau:

  1. Truy xuất một số ngẫu nhiên mới từ máy chủ để sử dụng khi tạo số chỉ dùng một lần nhằm liên kết với tính năng kiểm tra tính toàn vẹn
  2. Hãy gọi API Tính toàn vẹn của Play để tạo yêu cầu về tính toàn vẹn và nhận mã thông báo tính toàn vẹn có chứa kết quả
  3. Gửi mã thông báo lệnh và tính toàn vẹn tới máy chủ của bạn bằng cách sử dụng yêu cầu HTTP POST
  4. Xử lý và hiện kết quả

Thêm mã sau vào hàm integrityCommand trống:

        // Set our state to working to trigger a switch to the waiting UI
        _serverState.emit(ServerState(
            ServerStatus.SERVER_STATUS_WORKING))
        // Request a fresh random from the server as part
        // of the nonce we will generate for the request
        var integrityRandom = IntegrityRandom("", 0U)
        try {
            val returnedRandom = httpClient.get<IntegrityRandom>(
                SERVER_URL + "/getRandom")
            integrityRandom = returnedRandom
        } catch (t: Throwable) {
            Log.d(TAG, "getRandom exception " + t.message)
            _serverState.emit(ServerState(ServerStatus.SERVER_STATUS_UNREACHABLE,
                IntegrityRandom("", 0U)))
        }

        // If we have a random, we are ready to request an integrity token
        if (!integrityRandom.random.isNullOrEmpty()) {
            val nonceString = GenerateNonce.GenerateNonceString(TEST_COMMAND,
                integrityRandom.random)
            // Create an instance of an IntegrityManager
            val integrityManager = IntegrityManagerFactory.create(context)

            // Use the nonce to configure a request for an integrity token
            try {
                val integrityTokenResponse: Task<IntegrityTokenResponse> =
                    integrityManager.requestIntegrityToken(
                        IntegrityTokenRequest.builder()
                            .setNonce(nonceString)
                            .build()
                    )
                // Wait for the integrity token to be generated
                integrityTokenResponse.await()
                if (integrityTokenResponse.isSuccessful && integrityTokenResponse.result != null) {
                    // Post the received token to our server
                    postCommand(integrityTokenResponse.result!!.token(), integrityRandom)
                } else {
                    Log.d(TAG, "requestIntegrityToken failed: " +
                            integrityTokenResponse.result.toString())
                    _serverState.emit(ServerState(ServerStatus.SERVER_STATUS_FAILED_TO_GET_TOKEN))
                }
            } catch (t: Throwable) {
                Log.d(TAG, "requestIntegrityToken exception " + t.message)
                _serverState.emit(ServerState(ServerStatus.SERVER_STATUS_FAILED_TO_GET_TOKEN))
            }
        }

POST lệnh đến máy chủ của bạn đã được chia nhỏ thành một hàm postCommand riêng. Thêm mã sau vào hàm postCommand trống:

        try {
            val commandResult = httpClient.post<CommandResult>(
                SERVER_URL + "/performCommand") {
                contentType(ContentType.Application.Json)
                body = ServerCommand(TEST_COMMAND, tokenString)
            }
            _serverState.emit(ServerState(ServerStatus.SERVER_STATUS_REACHABLE,
                integrityRandom,
                commandResult.diagnosticMessage,
                commandResult.commandSuccess,
                commandResult.expressToken))
        } catch (t: Throwable) {
            Log.d(TAG, "performCommand exception " + t.message)
            _serverState.emit(ServerState(ServerStatus.SERVER_STATUS_UNREACHABLE))
        }

Khắc phục mọi tệp nhập bị thiếu và lưu tệp.

19. Hiện kết quả (Kotlin)

Cập nhật giao diện người dùng với dữ liệu tóm tắt kết quả

Giao diện người dùng hiện hiển thị văn bản giữ chỗ cho phần tóm tắt kết quả về tính toàn vẹn. Để thay thế phần giữ chỗ bằng dữ liệu tóm tắt thực tế, hãy thực hiện các bước sau:

  1. Trên ngăn Project (Dự án) trong Android Studio, hãy mở tệp MainView.kt trong start/app/src/main/java/com.example.google.codelab.playintegritykotlin/ui/main.
  2. Chuyển đến cuối hàm MainUI, tìm câu lệnh text = "None", và thay thế bằng mã sau:
                        text = state.serverState.serverVerdict,
  1. Khắc phục mọi tệp nhập bị thiếu và lưu tệp.

20. Tạo và tải lên (Kotlin)

Tạo và thiết lập kho khoá cho ứng dụng

Android yêu cầu tất cả các ứng dụng phải có chữ ký số cùng một chứng chỉ trước khi được cài đặt hoặc cập nhật trên một thiết bị.

Chúng ta sẽ tạo một Kho khoá cho ứng dụng trong lớp học lập trình này. Nếu bạn đang xuất bản bản cập nhật cho trò chơi hiện có, hãy sử dụng cùng một Kho khoá như khi bạn phát hành các phiên bản ứng dụng trước đó.

Tạo kho khoá và Gói ứng dụng cho bản phát hành

Làm theo các bước tại Kho khoá với Android Studio để tạo một kho khoá rồi sử dụng kho khoá này để tạo một bản phát hành có chữ ký của trò chơi. Trong Android Studio, hãy chọn Generate Signed Bundle/APK (Tạo gói/APK có chữ ký) trên trình đơn Build (Tạo) để bắt đầu quy trình xây dựng. Chọn lựa chọn App Bundle khi được nhắc chọn Android App Bundle hoặc APK. Khi kết thúc quy trình này, bạn sẽ có một tệp .aab phù hợp để tải lên Google Play Console.

Tải lên Play Console

Sau khi tạo một tệp Gói ứng dụng, hãy tải tệp đó lên Play Console. Bạn nên sử dụng kênh kiểm thử nội bộ để nhanh chóng truy cập vào bản dựng.

Chạy bản thử nghiệm

Bây giờ, bạn nên tải xuống và chạy bản thử nghiệm từ Cửa hàng Play. Bạn sẽ chọn thành công nút Call server with integrity check (Gọi máy chủ bằng tính năng kiểm tra tính toàn vẹn) và kết quả sẽ hiện như sau:

3291795e192396c9.png

21. Xin chúc mừng

Xin chúc mừng, bạn đã thêm thành công API Tính toàn vẹn của Play vào ứng dụng Android!

Tài liệu đọc thêm