### 影片簡介  - 示範如何使用 Google Play Billing Library 銷售應用內商品 - 涵蓋新增商品、啟動購買流程、後端驗證、確認購買、解鎖商品等流程 --- ### 實作 Billing Library 的準備工作   - 在 `AndroidManifest.xml` 加入網路權限 - 在 `build.gradle` 的 dependencies 中加入 Google Play Billing Library - 同步專案以套用變更 --- ### 測試環境設定       - 建立已簽署的 App Bundle - 登入 Google Play Console 並進入「License Testing」新增測試帳號 - 建立新應用,進入「Internal Testing」→「Create New Release」並上傳 App Bundle - 指定測試帳號,啟動內部測試版本  - 使用支援 Google Play 的模擬器登入測試帳號  - 複製測試邀請連結,在模擬器中用 Chrome 開啟並加入測試   `https://play.google.com/console/u/0/developers/ `==5131942709901165805== `/app/` ==4972066688623906047== `/tracks/` ==4701385257687167760== `?tab=testers` --- ### 新增應用內商品   - 在 Play Console 左側點選「Monetize」→「In-app Products」 - 點選「Create Product」,設定商品 ID、名稱、說明與價格 - 儲存並啟用商品 - 重複步驟建立兩個商品作為示範 --- ### 顯示商品資訊 - 在 `MainActivity` 宣告 BillingClient 並使用 Builder 模式建立實例 - 呼叫 `enablePendingPurchases()` 與設定 `PurchasesUpdatedListener` - 建立 `connectToGooglePlayBilling()` 方法,並呼叫 `startConnection()` - 在 `onBillingSetupFinished` 裡檢查連線狀態,若成功則呼叫 `getProductDetails()` - `getProductDetails()` 中建立商品 ID 清單並查詢商品資訊 - 使用 `querySkuDetailsAsync()` 查詢商品詳細資料 - 回傳結果後用 `TextView` 顯示商品名稱,`Button` 顯示價格 - 設定 XML 介面元件的 ID 並更新 UI 元件顯示商品資訊 - 確保在 BillingClient 建立後立即呼叫 `connectToGooglePlayBilling()` --- ### 啟動購買流程 - 為價格按鈕加入 `onClickListener` - 使用 `billingClient.launchBillingFlow` 來開啟購買流程 UI - 建立 `BillingFlowParams` 並設定 SKU 詳細資料 - 呼叫 `launchBillingFlow` 並傳入 context 與參數 --- ### 後端驗證購買 - 所有購買回傳會進入 `onPurchasesUpdated` callback - 驗證步驟一:確認購買狀態為 PURCHASED 且尚未 acknowledged - 驗證步驟二:將每筆購買的 token 傳送至後端驗證 - 若 token 從未被使用,代表為有效交易 - 成功驗證後,將購買資訊儲存至資料庫,並回傳訊息給 App --- ### 建立 Firebase Cloud Functions 專案 - 前往 [console.firebase.com](https://console.firebase.com) 建立專案 - 安裝 Node.js 與 Firebase CLI 工具 - 建立資料夾、登入 Firebase 並執行 `firebase init` - 選擇 Cloud Functions 功能並安裝相依套件 --- ### 撰寫後端驗證邏輯 - 在 `functions/index.js` 中建立驗證函數 - 建立 `purchaseInfo` JSON 物件,包含: - purchase token - order id - purchase time - isValid(預設為 false) - 初始化 Firebase Admin 並建立 Firestore 連線 - 驗證是否已存在該 purchase token 的文件 - 若存在,視為無效購買 - 若不存在,將 `isValid` 設為 true 並寫入 Firestore - 最後回傳驗證結果給 App --- ### 部署 Cloud Function 並整合至 App - 升級 Firebase 計劃至 Blaze(否則無法部署) - 使用 `firebase deploy` 命令部署函數 - 部署成功後複製函數的 Request URL - 將 URL 加入 Android App 中以便進行伺服器溝通 - App 呼叫此 URL 並根據伺服器回應判斷是否為有效購買 --- ### 使用 Volley 與 Cloud Functions 溝通 - 在 `build.gradle` 中加入 Volley 函式庫 - 建立 `confirmPurchase` 方法並接收 `Purchase` 物件 - 建立請求 URL,包含購買資料(token、時間、訂單 ID) - 使用 `StringRequest` 建立 POST 請求,傳送至 Cloud Functions - 建立 Volley 的 `RequestQueue` 並將請求加入佇列 - 在 `onPurchasesUpdated` callback 中呼叫驗證方法 - 至 Firebase Console 將 Firestore 的讀寫規則暫設為 true --- ### 使用 `acknowledgePurchase()` 確認一次性商品 - 預設情況下每筆購買只能購買一次 - 未確認的購買不會付款成功 - 使用 `acknowledgePurchase()` 來確認一次性商品 - 建立 `AcknowledgePurchaseParams` 並設置 purchase token - 呼叫 `billingClient.acknowledgePurchase()` 並處理回應 - 成功後可在回呼中執行解鎖邏輯,例如顯示 Toast 或解鎖功能 --- ### 使用 `consumeAsync()` 處理可重複購買商品 - 更換為可消耗商品(例如:遊戲幣) - 使用 `consumeAsync()` 來處理購買確認 - 建立 `ConsumeParams` 並設置 purchase token - 呼叫 `billingClient.consumeAsync()` 並處理回應 - 成功後可執行解鎖或給予物品邏輯,可重複購買 --- ### 處理 App 關閉期間的購買行為 - 不應只依賴 `onPurchasesUpdated()`,因為 App 關閉時無法觸發 - 建議在 `onResume()` 中處理未完成確認的購買 - 使用 `billingClient.queryPurchasesAsync()` 查詢已購買項目 - 逐一檢查購買狀態是否為已購買且尚未確認 - 對尚未確認的項目執行購買驗證與確認流程 --- ### Terminology - **Manifest 檔案(Manifest File)**:Android 應用的配置檔,聲明權限與元件。 - **INTERNET 權限(Internet Permission)**:允許應用存取網路的權限。 - **build.gradle**:用於配置應用模組與依賴項的 Gradle 檔案。 - **dependencies 區塊(Dependencies Section)**:定義應用所需的外部函式庫區域。 - **同步專案(Sync Project)**:將 Gradle 設定應用至專案的過程。 - **App Bundle**:Android 應用的發行格式,可減少安裝檔案大小。 - **Google Play Console**:開發者管理 Android 應用的平台。 - **License Testing**:用於測試應用內購與授權功能的設定區塊。 - **Internal Testing(內部測試)**:讓指定帳號測試尚未公開的應用版本。 - **Create Release**:建立應用版本發行流程。 - **Emulator(模擬器)**:模擬 Android 裝置的虛擬環境。 - **Android Virtual Device Manager(AVD Manager)**:管理與建立模擬器的工具。 - **Play Store 圖示(Play Store Icon)**:模擬器支援 Google Play 的識別標誌。 - **Sign In(登入)**:使用帳號登入 Google Play。 - **Opt-in 測試(Tester Opt-in)**:測試者接受測試邀請加入測試流程。 - **Monetize 區塊**:在 Google Play Console 中用於設定商品與營利策略的區塊。 - **In-app Products(應用內商品)**:可於應用內購買的虛擬項目。 - **Product ID**:商品的唯一識別碼,創建後無法更改。 - **Set Price**:設定商品價格的操作。 - **Activate(啟用)**:使商品在 Play 商店中上架生效。 - **MainActivity**:應用的主要邏輯控制類別。 - **BillingClient 變數**:管理 Google Play 購買流程的類別實例。 - **Builder 方法**:建構 BillingClient 物件所使用的設計模式方法。 - **enablePendingPurchases()**:啟用對暫掛交易的支援,是必須呼叫的方法。 - **PurchasesUpdatedListener**:接收購買更新事件的監聽器。 - **connectToGooglePlayBilling()**:建立與 Google Play 的連線方法。 - **startConnection()**:開始連線至 Billing Service 的方法。 - **BillingClientStateListener**:回報 BillingClient 連線狀態的監聽器。 - **onBillingServiceDisconnected()**:當服務中斷時的回呼方法。 - **onBillingSetupFinished()**:設定完成時的回呼方法。 - **BillingResult**:表示購買作業結果的物件。 - **querySkuDetailsAsync()**:非同步查詢 SKU 詳細資料的方法。 - **SkuDetailsParams**:查詢商品所需參數的資料結構。 - **setSkusList()**:設定要查詢的商品 ID 清單的方法。 - **setType()**:設定商品類型,如消費型或訂閱型。 - **SkuDetailsResponseListener**:取得 SKU 資訊查詢結果的回呼介面。 - **RecyclerView**:顯示大量資料的 UI 元件。 - **CardView**:以卡片方式呈現資料的 UI 元件。 - **TextView**:用來顯示文字的 UI 元件。 - **Button**:用來顯示或觸發操作的按鈕 UI 元件。 - **setText()**:設定 TextView 或 Button 顯示的文字方法。 - **getTitle()**:從 SkuDetails 取得商品標題的方法。 - **getPrice()**:從 SkuDetails 取得商品價格的方法。 - **findViewById()**:透過元件 ID 取得 UI 元件的函式。 - **Activity XML Layout**:定義 UI 結構的 XML 檔案。 - **ConstraintLayout**:可透過約束定義元件位置的佈局容器。 - **ID 命名(View ID)**:設定 UI 元件的唯一識別名稱。 - **TextView ID:item_name**:顯示商品名稱的元件 ID。 - **Button ID:item_price**:顯示商品價格的按鈕 ID。 - **run App(執行應用)**:啟動應用並觀察 UI 效果。 - **SKU(Stock Keeping Unit)**:商品的識別碼,一般代表單一可銷售項目。 - **暫掛交易(Pending Purchase)**:尚未完成或處理中的購買交易。 - **UI 顯示(UI Display)**:在應用畫面中顯示商品資訊的方式。 - **查詢商品細節(Get Product Details)**:從 Play Console 取得商品的詳細資料。 - **List 物件**:儲存多筆資料的集合型別,常用於 SKU ID 清單。 - **Builder 設計模式**:用來建構複雜物件的一種程式設計方法。 - **Product 資訊展示(Product Presentation)**:將產品資訊呈現在使用者介面中的作法。 - **OnClickListener**:用於監聽按鈕點擊事件的介面。 - **launchBillingFlow()**:啟動 Google Play 的購買流程 UI 方法。 - **BillingFlowParams**:用來設定購買流程參數的物件。 - **setSkuDetails()**:為購買流程設定商品資訊的方法。 - **onPurchasesUpdated()**:接收購買完成後結果的回呼方法。 - **purchase list**:儲存使用者已購買項目的清單物件。 - **response code**:BillingResult 中代表購買結果狀態的代碼。 - **Purchase.getPurchaseState()**:取得購買狀態的方法。 - **Purchase.isAcknowledged()**:檢查購買是否已確認的方法。 - **purchase token**:唯一識別單一交易的字串,用於驗證。 - **後端伺服器(Backend Server)**:應用用來處理邏輯與儲存資料的後端系統。 - **Firebase Cloud Functions**:Firebase 提供的無伺服器後端服務平台。 - **Firestore Database**:Firebase 提供的即時 NoSQL 資料庫。 - **firebase console**:管理 Firebase 專案的網頁後台介面。 - **firebase tools**:Firebase CLI 工具,用於本機管理與部署功能。 - **npm install -g firebase-tools**:安裝 Firebase CLI 的命令。 - **firebase init**:初始化 Firebase 專案與功能的命令。 - **functions/index.js**:定義雲端函式邏輯的主要檔案。 - **exports.functionName**:定義並匯出一個 Firebase 雲端函式的方法。 - **request handler function**:處理傳入 HTTP 請求的函式。 - **purchaseInfo(JSON)**:儲存購買資訊的資料物件。 - **orderId**:Google Play 提供的訂單編號。 - **purchaseTime**:商品購買時間。 - **isValid**:標記購買是否有效的布林值欄位。 - **req.query**:從請求網址查詢參數中取得資料的方式。 - **admin module**:Firebase Admin SDK,用來存取 Firestore 與其他服務。 - **admin.initializeApp()**:初始化 Firebase Admin SDK 的方法。 - **admin.firestore()**:取得 Firestore 實例的方法。 - **doc()**:存取 Firestore 文件的函式。 - **get()**:讀取指定文件資料的方法。 - **exists**:判斷文件是否存在的屬性。 - **set()**:將資料寫入指定文件的方法。 - **then()**:處理非同步操作完成後的回呼方法。 - **firebase deploy --only functions**:將雲端函式部署至 Firebase 的命令。 - **Blaze Plan**:Firebase 提供的按用量付費方案,必要條件以啟用部署功能。 - **request URL**:Firebase 雲端函式的存取網址,用於前後端溝通。 - **HTTP 請求(HTTP Request)**:應用與伺服器之間資料傳遞的方式。 - **非同步通訊(Asynchronous Communication)**:在不阻塞主執行緒下進行的伺服器互動。 - **資料驗證(Data Validation)**:確認資料真實性與一致性的過程。 - **token 重複檢查(Duplicate Token Check)**:驗證是否為未使用過的交易憑證。 - **回應通知(Response Notification)**:伺服器將驗證結果回傳給前端應用的動作。 - **JSON 物件(JSON Object)**:JavaScript 的資料格式,用來傳輸結構化資料。 - **資料結構(Data Structure)**:資料儲存與組織方式。 - **雲端部署(Cloud Deployment)**:將程式碼上傳至雲端平台以供執行的動作。 - **伺服器端邏輯(Server-side Logic)**:於伺服器中處理業務邏輯的程式碼。 - **驗證流程(Verification Flow)**:檢查交易合法性的整體程序。 - **HTTP GET 方法**:從伺服器讀取資料的標準請求方法。 - **Node.js**:JavaScript 執行環境,常用於撰寫 Firebase 函式。 - **request.query.purchaseToken**:從 HTTP 請求中取得購買憑證的方式。 - **雲端函式端點(Cloud Function Endpoint)**:供應用端呼叫的公開函式位址。 - **程式碼編輯器(Code Editor)**:撰寫與編輯程式碼的工具,如 VS Code。 - **終端機(Terminal)**:輸入命令與執行程式的工具介面。 - **資料回傳(Data Response)**:伺服器將資料發送回應用的過程。 - **資料查詢(Data Query)**:讀取資料庫中特定資料的操作。 - **集合(Collection)**:Firestore 中用來儲存多個文件的容器。 - **文件 ID(Document ID)**:Firestore 中識別單一文件的鍵值。 - **布林值(Boolean Value)**:只允許 true 或 false 的資料型別。 - **Volley**:一個 Android 網路通訊函式庫,用來執行 HTTP 請求。 - **StringRequest**:Volley 提供的類別,用來建立字串型態的 HTTP 請求。 - **POST 請求(POST Request)**:用來向伺服器傳送資料的 HTTP 方法。 - **RequestQueue**:Volley 的請求佇列,負責排程與執行網路請求。 - **Response.Listener**:收到伺服器回應時執行的回呼函式。 - **Response.ErrorListener**:請求失敗或錯誤時執行的回呼函式。 - **URL 查詢參數(Query Parameter)**:URL 中用來傳遞資料的鍵值對格式。 - **Key-Value Pair**:一種資料格式,由鍵(Key)與對應的值(Value)組成。 - **Ampersand(&)**:分隔多組查詢參數的符號。 - **Request URL**:發送 HTTP 請求的目標網路位置。 - **Firebase Console Firestore 規則(Firestore Rules)**:控制資料庫讀寫權限的安全規則。 - **acknowledgePurchase()**:Google Play Billing 中用來確認購買的 API 方法。 - **one-time purchase**:一次性購買的商品類型。 - **consumeAsync()**:用於消耗可重複購買商品的 API 方法。 - **AcknowledgePurchaseParams**:用於建立 acknowledgePurchase 請求參數的類別。 - **setPurchaseToken()**:設置要確認或消耗的購買憑證的方法。 - **AcknowledgePurchaseResponseListener**:處理 acknowledge 回應的監聽器。 - **Toast Message**:Android 中用來顯示暫時通知的 UI 元件。 - **“You already own this item” 錯誤**:表示尚未確認或消耗的商品無法再次購買。 - **ConsumeParams**:用於建立 consumeAsync 請求參數的類別。 - **ConsumeResponseListener**:處理 consumeAsync 回應的監聽器。 - **Multiple Purchase(多次購買)**:允許使用者多次購買相同商品的功能。 - **onResume() 方法**:當應用重新啟動時呼叫的 Activity 生命周期方法。 - **queryPurchasesAsync()**:用來查詢已購買商品的非同步方法。 - **ProductType.INAPP**:代表查詢的商品為應用內一次性商品。 - **PurchasesResponseListener**:回傳購買清單的回呼介面。 - **BillingResult.getResponseCode()**:取得請求回應碼的方法。 - **Purchase.PurchaseState.PURCHASED**:代表購買狀態為已購買的常數。 - **未確認購買(Unacknowledged Purchase)**:尚未呼叫 acknowledge 的購買交易。 - **購買驗證流程(Purchase Verification Flow)**:確認交易有效性的整體步驟。 - **背景交易處理(Background Purchase Handling)**:應用未開啟時處理購買的機制。 - **主動回查(Active Polling)**:應用主動查詢伺服器狀態的操作方式。 - **Firebase Blaze 計畫(Blaze Plan)**:Firebase 按用量計費方案,支援雲端部署。 - **Firebase Functions 部署(Function Deploy)**:將後端功能上傳到雲端執行的操作。 - **JSON Response 解析**:從伺服器回傳的 JSON 資料中解析所需欄位。 - **isValid 屬性**:代表此購買資料是否有效的欄位。 - **App Lifecycle(應用生命周期)**:Android 應用的啟動、暫停、恢復等階段流程。 - **Context 參數**:Android 中代表目前運行環境的物件,必要於多種 API 呼叫。 - **Builder 模式**:用於構建複雜參數物件的設計模式。 - **非同步回呼(Async Callback)**:操作完成後由系統通知的執行方法。 - **Firestore Collection 路徑**:儲存資料的集合在資料庫中的位置描述。 - **Firebase Admin SDK**:Firebase 用來存取雲端資源的後端 SDK。 - **Document ID(文件 ID)**:Firestore 中每筆資料的唯一識別碼。 - **Firebase CLI(命令列工具)**:本機與 Firebase 雲端進行互動的工具。 - **Node.js 環境**:執行 Firebase Cloud Functions 所需的 JavaScript 執行環境。 - **HTTP 請求錯誤處理(HTTP Error Handling)**:處理網路錯誤狀態的程式邏輯。 - **初始化 Firebase 專案(Firebase Init)**:建立雲端功能初始設定的流程。 - **Firebase Hosting**:Firebase 提供的靜態網站托管服務,與 Functions 搭配使用。 - **Key-Value URL 編碼(URL Encoding)**:將資料格式轉為瀏覽器可識別的查詢參數。 - **Firebase Function Endpoint 呼叫**:透過網路發送資料至 Firebase 雲端函式的方式。
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up