<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # 一、以下是消耗類和非消耗類的正常流程(訂閱類的不太清楚) 1.進入充值頁面,向app server獲取productIdList及展示信息。 2.用productIdList調iapsdk獲取productDetailList(用來發起支付的參數)。 3.用戶選擇一個productDetail,然后調iap sdk發起支付。 4.監聽到apple支付成功,將purshaseId、receipt發給app server。 5.app server 向apple server發起校驗請求,比對in_app數組里對應的purshaseId的校驗結果,返回給第4步app的請求。 6.app端收到成功結果后finish掉該productDetail。 # 二、以下是應對異常情況 a.上面第4步斷網或者app閃退。 b.上面第6步因為網絡原因沒有finish該productDetail。 針對第a種異常: i.下次進入app用iap sdk獲取未處理(未finish)棧里的productDetail(這個flutter iap plugin沒有提供方法,我自己fork后加了該方法)(注意這里是單數,只有一個未處理),然后接著走正常流程的4、5、6。 ii.再次購買時,先執行i的步驟,確保處理完畢了才能發起第二筆支付,否則獲取未處理productDetail為復數時會導致receipt紊亂導致校驗失敗造成卡單(未處理棧里一直在)。 針對第b種異常: a的異常處理會讓app server重復校驗,所以這里需要app server做一下記錄,校驗過的結果存在數據庫里,再發起該purshaseId校驗直接返回結果,避免重復增加余額。 # 三、編碼參考 環境: flutter版本: v1.9.1+hotfix.4 插件依賴:in_app_purchase: ``` git: url: https://github.com/qq326646683/plugins.git ref: 13df320b6112a3a4abfbec47bba53b2f95402637 path: packages/in_app_purchase ``` ``` balance_page.dart: @override void initState() { InappPurchaseService.getInstance().initListener(context); super.initState(); /// 步驟1 ResponseResult<List<AppleProduct>> response = await OrderService.getInstance().getAppleProduct(); if (response.isSuccess) { /// 步驟2 _initStoreInfo(response.data); } } @override void dispose() { InappPurchaseService.getInstance().removeListener(); super.dispose(); } _initStoreInfo(List<AppleProduct> appProductList) async { productDetailList = await InappPurchaseService.getInstance().initStoreInfo(context, appProductList); } build() { ... SMClickButton( /// 步驟3 onTap: () => InappPurchaseService.getInstance().toCharge(productDetailList, selectIndex, context), child: Container( width: _Style.btnContainerW, height: _Style.bottomContainer, color: SMColors.btnColorfe373c, alignment: Alignment.center, child: Text('確認充值', style: SMTxtStyle.colorfffdp16,), ), ), } ``` ``` inapp_purchase_service.dart: initListener(BuildContext context) { final Stream purchaseUpdates = InAppPurchaseConnection.instance.purchaseUpdatedStream; _subscription = purchaseUpdates.listen((purchases) { _listenToPurchaseUpdated(context, purchases); }, onDone: () => _subscription.cancel(), onError: (error) => LogUtil.i(InappPurchaseService.sName, "error:" + error)); } void _listenToPurchaseUpdated(BuildContext context, List<PurchaseDetails> purchaseDetailsList) { purchaseDetailsList.forEach((PurchaseDetails purchaseDetails) async { if (purchaseDetails.status == PurchaseStatus.pending) { LogUtil.i(InappPurchaseService.sName, 'PurchaseStatus.pending'); LoadingUtil.show(context); } else { LoadingUtil.hide(); if (purchaseDetails.status == PurchaseStatus.error) { ToastUtil.showRed("交易取消或失敗"); } else if (purchaseDetails.status == PurchaseStatus.purchased) { ToastUtil.showGreen("交易成功,正在校驗"); LogUtil.i(InappPurchaseService.sName, "purchaseDetails.purchaseID:" + purchaseDetails.purchaseID); LogUtil.i(InappPurchaseService.sName, "purchaseDetails.serverVerificationData:" + purchaseDetails.verificationData.serverVerificationData); /// 步驟4 _verifyPurchase(purchaseDetails, needLoadingAndToast: true, context: context); } } }); } // return bool needLock Future<bool> _verifyPurchase(PurchaseDetails purchaseDetails, {bool needLoadingAndToast = false, BuildContext context}) async { Map param = { "transactionId" : purchaseDetails.purchaseID, "receipt": purchaseDetails.verificationData.serverVerificationData, }; if (needLoadingAndToast) LoadingUtil.show(context); ResponseResult<dynamic> response = await ZBDao.charge(param); if (needLoadingAndToast) LoadingUtil.hide(); if (response.isSuccess) { if (response.data == true) { /// 步驟6 await InAppPurchaseConnection.instance.completePurchase(purchaseDetails); if (needLoadingAndToast) ToastUtil.showGreen('充值成功'); OrderService.getInstance().getBalance(); return false; } else { if (needLoadingAndToast) ToastUtil.showRed('充值失敗'); return true; } } else { LogUtil.i(InappPurchaseService.sName, '處理失敗'); return true; } } Future<List<ProductDetails>> initStoreInfo(BuildContext context, List<AppleProduct> appleProductList) async { final bool isAvailable = await _connection.isAvailable(); if (!isAvailable) { return null; } List<String> productIdList = []; for(AppleProduct appleProduct in appleProductList) { productIdList.add(appleProduct.productId); } LoadingUtil.show(context); ProductDetailsResponse productDetailResponse = await _connection.queryProductDetails(productIdList.toSet()); LoadingUtil.hide(); if (productDetailResponse.error != null) { return null; } if (productDetailResponse.productDetails.isEmpty) { return null; } return productDetailResponse.productDetails; } void toCharge(List<ProductDetails> productDetailList, int selectIndex, BuildContext context) async { if (productDetailList == null) { ToastUtil.showRed("productDetailList為空"); return; } LoadingUtil.show(context); /// a異常ii步驟 bool needLock = await checkUndealPurshase(); LoadingUtil.hide(); if (needLock) { ToastUtil.showRed("有訂單未處理"); return; } final PurchaseParam purchaseParam = PurchaseParam(productDetails:productDetailList[selectIndex]); InAppPurchaseConnection.instance.buyConsumable(purchaseParam: purchaseParam); } // return bool needLock Future<bool> checkUndealPurshase() async { /// a.異常i步驟,這里在進入app后,用戶獲取登錄狀態后調用 LogUtil.i(InappPurchaseService.sName, '獲取未處理list'); try { List<PurchaseDetails> purchaseDetailsList = await _connection.getUndealPurchases(); if (purchaseDetailsList.isEmpty) return false; LogUtil.i(InappPurchaseService.sName, '處理數組最后一個'); PurchaseDetails purchaseDetails = purchaseDetailsList[purchaseDetailsList.length - 1]; return _verifyPurchase(purchaseDetails); } catch(e) { ToastUtil.showRed('同步蘋果支付信息失敗'); return true; } } ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看