Giữ chính sách quyền riêng tư đồng bộ với bản build
Chính sách quyền riêng tư được viết một lần và lỗi thời ngay khi một pull request thêm SDK. Cách phát hiện ngay trên pull request, bằng một bước kiểm tra miễn phí chỉ đọc tệp build.
Ghi lại các SDK, loại dữ liệu và quyền mà các trang của bạn được viết dựa trên, rồi so sánh tệp build của mỗi pull request với bản ghi đó. Khi xuất hiện một phụ thuộc hoặc quyền mà bản ghi không có, pull request sẽ cho thấy điều đó trước khi bản phát hành ra mắt — lúc chính sách quyền riêng tư và các biểu mẫu của cửa hàng vẫn còn dễ cập nhật.
Làm việc này trong vài phút thay vì thế
AppFoyer lưu trữ các trang mà hướng dẫn này nói đến — chính sách quyền riêng tư, điều khoản, hỗ trợ, xóa tài khoản và app-ads.txt — trên subdomain riêng của ứng dụng, không cần tên miền hay máy chủ của riêng bạn. Một ứng dụng được miễn phí, và không có gì cửa hàng yêu cầu lại bị đặt sau tường phí.
Đã kiểm tra ngày 30 tháng 9, 2026. Chính sách của cửa hàng thay đổi, đôi khi không báo trước. Mọi thứ dưới đây đều dẫn liên kết đến tài liệu chính thức, và trang đó — không phải trang này — mới là căn cứ. Nếu hai bên mâu thuẫn, cửa hàng là đúng. Hướng dẫn này được dịch từ tiếng Anh; các trích dẫn từ tài liệu của cửa hàng được giữ nguyên bản tiếng Anh.
Viết chính sách quyền riêng tư là việc làm một lần. Giữ cho nó đúng thì không: chính sách mô tả bản build bạn có lúc viết, còn bản build thì liên tục thay đổi. Một pull request thêm báo lỗi sự cố, một thư viện gói đăng ký hay quyền truy cập vị trí, ứng dụng được phát hành, và chính sách, biểu mẫu Data safety cùng App Privacy details vẫn mô tả ứng dụng cũ.
Cả hai cửa hàng đều coi đó là vấn đề của bạn, không phải của họ. Google Play nói các câu trả lời Data safety của bạn phải luôn chính xác và đầy đủ, và dữ liệu được thu thập bởi các thư viện và SDK bên thứ ba trong ứng dụng là thứ bạn phải khai báo. Apple nói điều tương tự về App Privacy details, và thêm rằng bạn có thể thay đổi câu trả lời trong App Store Connect bất cứ lúc nào mà không cần gửi bản cập nhật.
Sự lệch pha thực sự đến từ đâu
Hầu như không bao giờ đến từ quyết định “thu thập thêm dữ liệu”. Nó đến từ công việc kỹ thuật bình thường:
- Một phụ thuộc mới. Báo lỗi sự cố, phân tích, SDK paywall, thư viện bản đồ.
- Một quyền mới. Vị trí cho một tính năng, máy ảnh cho trình quét, theo dõi cho quảng cáo.
- Một flavor hoặc target. Bản build miễn phí có thêm SDK quảng cáo mà bản trả phí không có.
- Một thứ bị gỡ bỏ. Cũng là lệch pha — giờ chính sách khai báo thừa, đó là lỗi an toàn hơn nhưng vẫn là lỗi.
Mọi thay đổi này đều nằm trong một tệp build — build.gradle, AndroidManifest.xml, Podfile,
Package.swift, Info.plist, pubspec.yaml, package.json. Đó là điều khiến nó kiểm tra được.
Cách tiếp cận: một bản ghi, và kiểm tra trên mỗi pull request
- Khi các trang được viết, hãy ghi lại chúng được viết dựa trên gì: các SDK, loại dữ liệu và quyền trong bản build tại thời điểm đó.
- Trên mỗi pull request, đọc lại các tệp build và so sánh.
- Khi có gì khác biệt, nói rõ cái gì, ở đâu (tệp và dòng), và trang hay biểu mẫu nào có thể bị ảnh hưởng.
Hai đặc tính là quan trọng. Bước kiểm tra phải chỉ đọc tệp build — không bao giờ đọc mã nguồn, không bao giờ đọc bí mật — để chạy an toàn trên bất kỳ repository nào. Và nó phải nói “có thể đã lỗi thời”, không phải “vi phạm”: một thư viện trong tệp build không chứng minh ứng dụng dùng nó, và chỉ bạn mới biết nó có thay đổi những gì ứng dụng thu thập hay không.
Thiết lập với AppFoyer
Bước kiểm tra này miễn phí trên mọi gói. Nó chỉ đọc tệp build, không cần key hay bí mật, không gửi gì đi đâu và không bao giờ thay đổi một trang nào.
Với plugin Claude Code
- Nói “make this app store-ready” (làm cho ứng dụng này sẵn sàng lên cửa hàng). Ngoài việc soạn các
trang, plugin viết
appfoyer.jsonở thư mục gốc của repository: bản ghi về những gì các trang được viết dựa trên. - Nói “add the AppFoyer drift check” (thêm bước kiểm tra lệch pha AppFoyer). Nó cho bạn xem một
GitHub workflow và viết
.github/workflows/appfoyer.ymlkhi bạn đồng ý. - Commit cả hai tệp. Plugin không bao giờ commit hay push thay bạn.
Không dùng plugin
Tự thêm workflow:
name: AppFoyer drift check
on: pull_request
permissions:
contents: read
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: appfoyer/check-action@v1
Mở một pull request. Khi repository chưa có appfoyer.json, phần tóm tắt job sẽ hiển thị tệp mà nó sẽ
viết từ bản build của bạn. So sánh với các trang đã công bố rồi commit nó.
Hoặc tạo cục bộ — cùng trình quét đó, được phát hành trên npm:
npx @appfoyer/check init
Trên hệ thống CI khác
Gói npm chạy ở bất cứ đâu chạy được Node 20 trở lên. Ví dụ với GitLab:
appfoyer-drift-check:
image: node:22
script:
- npx -y @appfoyer/check --fail-on-drift
--format markdown cho ra báo cáo giống như phần tóm tắt job trên GitHub; --format json dành cho
script.
Một phát hiện trông như thế nào
Một pull request thêm RevenueCat vào ứng dụng có các trang được viết khi chưa có nó:
"Trail Notes": 2 changes
+ In-app purchases / subscriptions (data collected) app/build.gradle.kts:28
→ Privacy policy may not declare "In-app purchases / subscriptions"
→ Google Play Data safety and Apple App Privacy answers may be outdated
→ Terms may not cover purchases and subscriptions
+ RevenueCat (SDK) app/build.gradle.kts:28
→ Store forms: RevenueCat is not in the app's SDK list
→ Privacy policy may not name this SDK
Theo mặc định, job báo cáo và vẫn pass. Thêm fail-on-drift: "true" dưới with: để nó fail cho đến
khi bản ghi được cập nhật.
Khi nó báo có thay đổi
- Cập nhật những gì thay đổi ảnh hưởng tới. Nói lại “make this app store-ready” trên cùng
branch: plugin đọc lại bản build, cập nhật thông tin của ứng dụng, soạn lại các trang mà thay đổi
chạm tới và viết lại
appfoyer.json. Hoặc tự chỉnh sửa các trang và tab Store forms trong dashboard. - Làm mới bản ghi. Plugin đã làm việc này. Sau khi chỉnh sửa trên dashboard, chạy
npx @appfoyer/check update, hoặc sao chép tệp đã làm mới từ phần tóm tắt job, nơi nó nằm bên dưới các phát hiện. - Commit nó trong cùng pull request. Lần chạy tiếp theo sẽ không báo thay đổi, và lịch sử cho thấy phụ thuộc và thay đổi về phần công bố đến cùng nhau.
- Cập nhật biểu mẫu cửa hàng trong các console. Cả bước kiểm tra lẫn AppFoyer đều không truy cập được Play Console hay App Store Connect. Câu trả lời nháp nằm trong tab Store forms của dashboard.
- Công bố các bản nháp đã cập nhật từ màn hình xem lại.
Nhiều ứng dụng trong một repository
appfoyer.json chứa một mục cho mỗi trang thông tin ứng dụng trên cửa hàng. Một product flavor có
application id riêng sẽ có mục riêng, nên một SDK quảng cáo chỉ dùng trong flavor miễn phí được so sánh
với các trang của flavor miễn phí chứ không phải của bản trả phí. Plugin viết một mục cho mỗi flavor mà
nó đã làm cho sẵn sàng lên cửa hàng. Khi viết tay, một mục nhận danh sách sourceSets — ["free"],
hoặc với bản build nhiều chiều thì mọi flavor trong tổ hợp cộng với chính tổ hợp đó — và một thư mục
root khi ứng dụng nằm trong một monorepo.
Những gì nó không thấy được
- Phụ thuộc của phụ thuộc, trừ trên iOS, nơi
Podfile.lockliệt kê chúng. Một SDK được kéo vào bởi một thư viện khác không xuất hiện trong tệp build của bạn, nên cũng không xuất hiện ở đây. - Cấu hình chỉ có trong mã.
app.config.js/app.config.tstrong Expo là JavaScript và không được đọc;app.jsonvàpackage.jsonthì có. - Bạn có dùng những gì bạn khai báo hay không. Một phụ thuộc có mặt nhưng không được dùng vẫn bị báo cáo.
- Backend của bạn. Không có gì trong tệp build nói máy chủ của bạn lưu gì hay lưu bao lâu.
Đây là lời nhắc vào đúng thời điểm việc công bố một thay đổi là rẻ nhất, không phải phán quyết về tuân thủ và không phải lời khuyên pháp lý.
Nguồn chính thức
- Provide information for Google Play’s Data safety section — Google Play Console Help: giữ biểu mẫu chính xác, và dữ liệu của SDK bên thứ ba
- App privacy details on the App Store — Apple: giữ câu trả lời cập nhật, và cập nhật chúng mà không cần bản cập nhật ứng dụng
appfoyer/check-actionvà@appfoyer/check— Action và gói npm, kèm những gì chúng đọc