React-native-iap: 自動更新サブスクリプションがまだアクティブかどうかをIOSがチェックします

作成日 2018年09月27日  ·  61コメント  ·  ソース: dooboolab/react-native-iap

react-native-iapのバージョン

2.2.2

エラーに直面したプラットフォーム(IOSまたはAndroid、あるいはその両方?)

IOS

予想される行動

RNIAP APIを使用して、自動更新サブスクリプションがまだアクティブであるかどうかを確認できます

実際の動作

これをチェックするためにAndroidのIMでこれを行っています:

export const isUserSubscriptionActive = async (subscriptionId) =>{
    // Get all the items that the user has
    const availablePurchases = await getAvailablePurchases();
    if(availablePurchases !== null && availablePurchases.length > 0){
        const subscription = availablePurchases.find((element)=>{
            return subscriptionId === element.productId;
        });
        if(subscription){
             // check for the autoRenewingAndroid flag. If it is false the sub period is over
              return subscription["autoRenewingAndroid"] == true;
            }
        }else{
            return false;
        }
    }
}

iOSでは、それをチェックするフラグはありません。getAvailablePurchasesメソッドは、現在アクティブでないサブスクリプションも含め、行われたすべての購入を返します。

これを確認する方法はありますか?

よろしく、
マルコス

📱 iOS 🚶🏻 stale

最も参考になるコメント

これが私が使用しているAndroidとiOSの両方で機能する関数であり、iOSで適切に並べ替えて、最新のレシートデータを確実に取得できるようにします。

import * as RNIap from 'react-native-iap';
import {ITUNES_CONNECT_SHARED_SECRET} from 'react-native-dotenv';

const SUBSCRIPTIONS = {
  // This is an example, we actually have this forked by iOS / Android environments
  ALL: ['monthlySubscriptionId', 'yearlySubscriptionId'],
}

async function isSubscriptionActive() {
  if (Platform.OS === 'ios') {
    const availablePurchases = await RNIap.getAvailablePurchases();
    const sortedAvailablePurchases = availablePurchases.sort(
      (a, b) => b.transactionDate - a.transactionDate
    );
    const latestAvailableReceipt = sortedAvailablePurchases[0].transactionReceipt;

    const isTestEnvironment = __DEV__;
    const decodedReceipt = await RNIap.validateReceiptIos(
      {
        'receipt-data': latestAvailableReceipt,
        password: ITUNES_CONNECT_SHARED_SECRET,
      },
      isTestEnvironment
    );
    const {latest_receipt_info: latestReceiptInfo} = decodedReceipt;
    const isSubValid = !!latestReceiptInfo.find(receipt => {
      const expirationInMilliseconds = Number(receipt.expires_date_ms);
      const nowInMilliseconds = Date.now();
      return expirationInMilliseconds > nowInMilliseconds;
    });
    return isSubValid;
  }

  if (Platform.OS === 'android') {
    // When an active subscription expires, it does not show up in
    // available purchases anymore, therefore we can use the length
    // of the availablePurchases array to determine whether or not
    // they have an active subscription.
    const availablePurchases = await RNIap.getAvailablePurchases();

    for (let i = 0; i < availablePurchases.length; i++) {
      if (SUBSCRIPTIONS.ALL.includes(availablePurchases[i].productId)) {
        return true;
      }
    }
    return false;
  }
} 

全てのコメント61件

私もこれを理解するために取り組んでいます。 私はまだテストしていませんが、私が読んでいることから、iTunes Connectで「共有シークレット」を作成し、これをキー「password」でvalidateReceiptIosに渡すことで可能であることがわかりました。 これにより、サブスクリプションの検証ステータスを示すコードと、サブスクリプションのステータスを判断するために使用できるキーlatest_receipt、latest_receipt_info、latest_expired_receiptinfoなどを含むJSONオブジェクトが返されると思います。 私は文字通りこれを理解しているだけなので、まだテストしていません。 それは私が問題とAppleのドキュメントからまとめているものです。 これが機能する場合は、問題に埋もれているのではなく、ドキュメントで非常に明確にする必要があります。
次のリンクが関連していると思います。
https://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html

203#237

編集:私は上記のプロセスが機能することを確認できます。 ドキュメントでこれを完全に説明するために作業する必要があると思います。 アプリの起動時に次のようなものを実装して、サブスクリプションの有効期限が切れているかどうかを判断します。

RNIap.getPurchaseHistory()
        .then(purchases => {
                RNIap.validateReceiptIos({
                   //Get receipt for the latest purchase
                    'receipt-data': purchases[purchases.length - 1].transactionReceipt,
                    'password': 'whateveryourpasswordis'
                }, __DEV__)
                    .then(receipt => {
                       //latest_receipt_info returns an array of objects each representing a renewal of the most 
                       //recently purchased item. Kinda confusing terminology
                        const renewalHistory = receipt.latest_receipt_info
                       //This returns the expiration date of the latest renewal of the latest purchase
                        const expiration = renewalHistory[renewalHistory.length - 1].expires_date_ms
                       //Boolean for whether it has expired. Can use in your app to enable/disable subscription
                        console.log(expiration > Date.now())
                    })
                    .catch(error => console.log(`Error`))
        })

@kevinEsherick

素晴らしい!

あなたのコードについてとても些細なことではないいくつかのこと。

  1. そのはず

const Expiration =

代わりに(おそらく単なるタイプミス)

const Expiration =

2)「パスワード」が何であるかを知らない人のために:「何でもあなたのパスワードは」:

アプリ内ページの共有秘密鍵を作成して、アプリで使用できます

手順は次のとおりです: https

+1してドキュメントを更新します。また、 @ dooboolabを使用すると、IOSとAndroidのユースケースを分けることができます。いくつかの違いがあるようです。 あなたが望むなら私はあなたを助けることができます。

よろしく

@kevinEsherick

自動更新サブスクリプションはどうなりますか?

Expires_date_msが最初の有効期限であるようですが、更新されていません

私はこれをテストしました:

  1. サブスクリプションアイテムをサブスクライブする
  2. 賞味期限を確認してください(5分後など)
  3. 10分待つ
  4. まだアクティブなサブスクリプションは自動更新サブスクリプションのようです
  5. 最後の更新レシートの有効期限がポイント2と同じであることを確認した場合

何か案は?

残念ながら、賞味期限が更新されているようです。少し時間がかかります。

誰かが同じシナリオにいる場合に備えて、このコメントをここに残しておきます。

よろしく

  1. そのはず

const Expiration =

代わりに(おそらく単なるタイプミス)

const Expiration =

おっと、あなたは正しいです、それはタイプミスでした。 意味をわかりやすくするために名前を変更しましたが、すべての出現箇所を変更するのを忘れていました。 編集しました、ありがとう。

そして、有効期限のある正確なシナリオはありませんでしたが、自動更新されないものがいくつかありましたが、それはどういうわけかそれ自体で解決しました(心配ですが、他に何をすべきかを再現することはできません)。 あなたが抱えていた問題はかなり一般的なものです。 これはApple側で予想される動作であるため、ユーザーのサブスクリプションを解除する前に、サブスクリプションを更新するためのバッファー期間を残す必要があります。 SOに関するこの問題は、より詳細に説明しています: https

ありがとう! 素晴らしい情報、理由かもしれません

この問題については、 @ kevinEsherickコードをドキュメントに含める必要があると思います👍登録者を確認するのに最適な方法です!

はい。 PRをリクエストされた方がいらっしゃいましたら、 readmeきちんとしたドキュメントをいただければ幸いです。 ありがとう。

こんにちは、みんな。 readmeにQ&Aセクションを追加しました。 誰かがこの問題のために私たちにPRを与えることができることを願っています。

今後数日でPRを行うことを検討します:)

また、このライブラリをサブスクリプション専用に使用したいと考えています。 iOSとAndroidの両方。 ユーザーが有効なサブスクリプションを持っているかどうかを判断する適切な方法を文書化していただければ幸いです。 😄

@curiousdustinこれに関するAppleの実装は、 mediumを参照すると本当にひどいものです。 バックエンドでこの種の処理を行う必要があるため、モジュールでこれを完全にサポートすることはできませんでした。 ただし、iOSサブスクリプション製品では機能しないメソッドgetAvailablePurchasesを使用して、AndroidでavailablePurchasesを取得できます。

それで、 @ marcosmartinez7@kevinEsherickがこのスレッドで取り組んでいる解決策は解決策ではなく、iOSサブスクリプションのステータスを確認するためにApple以外のバックエンドサーバーが必要だと言っていますか?

Appleのドキュメントと一緒に投稿したMediumの記事を読むと、サーバーを使用することが望ましいようですが、デバイスのみでサブスクリプションのステータスを判断することは不可能ではありません。

文章の一部の情報を見逃してしまい申し訳ありません。 これを管理します。
Appleは、中間者攻撃を防ぐために、 receiptを自分のサーバーに保存することを提案します。 したがって、後でそのレシートをチェックして、レシートが有効であるか、サブスクリプションがまだ利用可能であるかを確認できます。

ただし、 @ marcosmartinez7@kevinEsherickがうまくいった所有のAppleサーバー(サンドボックスと本番)に検証レシートの直接フェッチを提供しているため、 react-native-iap試してみるのは不可能ではありません。

私は現在、これがiosサブスクリプションをチェックするための解決策だと思います。

こんにちは、数日以上経ちました。仕事に追われましたが、READMEを更新するためにそのPRを送信します。 @curiousdustin上記で書いた方法は間違いなく機能し、ドキュメントに追加します。 今夜または明日PRを提出します:)

アップデートに感謝します。

あなたの例からもう1つ気づきました。

'receipt-data':purchases [purchases.length-1] .transactionReceipt、
..。
const Expiration = renewalHistory [renewalHistory.length-1] .expires_date_ms

私のテストでは、購入と更新履歴は必ずしも特定の順序である必要はありません。 意図したものを使用していることを確認するために、それらを並べ替える必要はありませんか?

こっちも一緒。 PurchasesとrenewalHistoryは間違いなく注文されていないため、最初に並べ替える必要があります。 開発では、それは多くの反復になることになります。

これが私が使用しているAndroidとiOSの両方で機能する関数であり、iOSで適切に並べ替えて、最新のレシートデータを確実に取得できるようにします。

import * as RNIap from 'react-native-iap';
import {ITUNES_CONNECT_SHARED_SECRET} from 'react-native-dotenv';

const SUBSCRIPTIONS = {
  // This is an example, we actually have this forked by iOS / Android environments
  ALL: ['monthlySubscriptionId', 'yearlySubscriptionId'],
}

async function isSubscriptionActive() {
  if (Platform.OS === 'ios') {
    const availablePurchases = await RNIap.getAvailablePurchases();
    const sortedAvailablePurchases = availablePurchases.sort(
      (a, b) => b.transactionDate - a.transactionDate
    );
    const latestAvailableReceipt = sortedAvailablePurchases[0].transactionReceipt;

    const isTestEnvironment = __DEV__;
    const decodedReceipt = await RNIap.validateReceiptIos(
      {
        'receipt-data': latestAvailableReceipt,
        password: ITUNES_CONNECT_SHARED_SECRET,
      },
      isTestEnvironment
    );
    const {latest_receipt_info: latestReceiptInfo} = decodedReceipt;
    const isSubValid = !!latestReceiptInfo.find(receipt => {
      const expirationInMilliseconds = Number(receipt.expires_date_ms);
      const nowInMilliseconds = Date.now();
      return expirationInMilliseconds > nowInMilliseconds;
    });
    return isSubValid;
  }

  if (Platform.OS === 'android') {
    // When an active subscription expires, it does not show up in
    // available purchases anymore, therefore we can use the length
    // of the availablePurchases array to determine whether or not
    // they have an active subscription.
    const availablePurchases = await RNIap.getAvailablePurchases();

    for (let i = 0; i < availablePurchases.length; i++) {
      if (SUBSCRIPTIONS.ALL.includes(availablePurchases[i].productId)) {
        return true;
      }
    }
    return false;
  }
} 

@andrewze

Androidシナリオでは、サブスクリプションが自動更新可能である場合、availablePurchasesで返されます

@curiousdustin @andrewzeyそうです、購入は注文されていません。 ただし、renewalHistory / latest_receipt_infoは常に注文されます。 購入が注文されていないことに気付いたのを覚えていますが、これが実際には問題ではないという何らかの理由を見つけたと思いました。 家に帰ってから数時間でこれを調べます。 これがわかるまで、PRを提出したくありません。
編集:購入を並べ替える必要がないと思う理由は、クエリした購入に関係なく、expires_date_msが同じ値を返すためです。 これはあなたたちにとって同じではありませんか? または、並べ替えが必要な情報が少しありますか? あなたの考えを聞かせてください。 私は、購入が時系列で注文されていないことをドキュメントが明確にする必要があることに同意しますが、私が知る限り、有効期限を取得するために並べ替えは必要ありません。

@kevinEsherickありがとう! 私の場合、購入も更新履歴も注文されていません。

@kevinEsherick @andrewzey皆さんはこのソリューションにPRを与えることができますか? 苦しんでいる他の人たちと分かち合いたいと思います。

確かに、公開アプリの起動が完了したらすぐに準備します=)。

私は私の最後のコメントに関するさらなる会話を待っていました。 私は未解決のままであるいくつかの問題を提起しました。 上記を参照してください。 それが整理されたら、私たちの1人がPRを行うことができます。

@kevinEsherickああ、すみません、私はそれを逃しました。

expires_date_msは、更新の領収書ごとに私にとって間違いなくユニークです。 おそらく私は誤解しましたか? デコードされた各レシートに添付されている更新レシート配列は、選択されているレシートに関係なく同じであることに気付きました。そのため、次の(私の例から)必要がないことがわかります。

const sortedAvailablePurchases = availablePurchases.sort(
      (a, b) => b.transactionDate - a.transactionDate
    );

しかし、私はとにかく正確にしようとし、Appleが文書化したものからの実際のAPI応答で起こりうる矛盾を補うためにそれをしました。 自動更新サブスクリプションで発生する可能性のあるレシートの総数を考えると、ソート操作にそれほど費用がかかるとは思いません。

PRにETAはありますか? このケースをまったく処理しないため、このパッケージからの移行を検討しています。

@schumannd PRはドキュメントの更新のみであるため、ここでreact-native-iap移動できます。

最近リリースされたアプリで、コードスニペットが実際に問題なく動作することを確認しました: https

編集私は間違いなくPRを作成します(Trelloの「Giveback to OSS」リストにあります)が、ブラックフライデーの週末の狂気の後😄

@ schumannd @ andrewzeyが言ったことを2番目に。 PRが言うことはすべてこの投稿に含まれています。 私はそれを回避するつもりでしたが、何をする必要があるかを正確に整理するのに時間がかかりました。それは旅行と多忙なスタートアップ時間と混ざり合って、私はまだそれをPRする時間がなかったことを意味します。 私はまだすぐに計画していますが、他の誰もが望むならその間にステップアップすることができます。 そして@andrewzeyは男を祝福します! よさそうだ、ダウンロードしてあげよう!

このスレッドがiOSで自動更新サブスクリプションを管理する正しい方法を正確に文書化しているとは確信していませんが、代わりに、このライブラリによって公開されているAPIごとの「回避策」ワークフローについて説明しています。 しかし、これは完全に私の側の推測であり、私は間違っている可能性があることを十分に認識しているので、以下に概説する観察についてフィードバックをお願いします。

私はReactNativeで自動更新サブスクリプションを管理する正しい方法を何週間も無駄に研究してきたので、ギアを切り替えて、Objective-C / Swiftでネイティブに管理する方法を研究し始めました。 これにより、ネイティブのStoreKit APIと文書化された使用法を、このライブラリに実装されているものと比較するための参照ポイントが得られました。

この記事は、サブスクリプションの購入、検証、および復元をネイティブiOSアプリで処理する方法についてこれまでに見つけた最良の説明です: httpsreact-native-iapで使用されている間、それらは異なるワークフローを実装しています。

私が見る主な違いは、 appStoreReceiptUrlです。

StoreKitはappStoreReceiptUrlを提供します。これは、私の理解では、iOSアプリの現在の購入/レシート情報をロードする正しい方法です。 これはreact-native-iapコードで使用および参照されていますが、参照されている記事に記載されているワークフローとは異なるコンテキストにあるようです。

この実装の違いが問題になるかどうか/どのように問題があるかはわかりませんが、 react-native-iap APIは、StoreKitのrestoreCompletedTransactionsに不必要な依存関係を作成しているようです。これは、最終的にgetPurchaseHistoryと呼ばれます。

react-native-iap APIは、iOSの次のワークフローをサポートする必要があるようです。

  • アプリケーションの起動時に( appStoreReceiptUrl介して)現在のアプリの領収書を読み込もうとします
  • 領収書を検証する機会を提供する
  • appStoreReceiptUrlがnullの場合、現在のデバイスで「復元」を開始すると、 appStoreReceiptUrlの値が設定され、検証ロジックを再試行できます。

考え?

繰り返しになりますが、このライブラリの実装または参照されているネイティブ実装を誤解している可能性があります。

@sellmeadog

あなたがリンクした記事でも言及されている重要なポイントはこれだと思います:

注:プロジェクトアプリはSelfieServiceを実行します。これは、領収書を受け取り、Appleの領収書検証サービスに直接アップロードします。 これは、サブスクリプションの設定に焦点を当てたチュートリアルを維持するための「チート」です。 実際のアプリでは、アプリではなく、リモートサーバーを使用する必要があります。

自動更新可能なサブスクリプション全体を理解するのに少し時間がかかりましたが、それを処理するための最良の方法は、信頼できる唯一の情報源として独自のバックエンドを使用することです。

  • すべてのトランザクションデータをすぐにバックエンドに送信します
  • 送信に問題が発生した場合に再送信する手段を提供する(購入の復元など)
  • 定期的に(たとえば、1日1回)バックエンドに保存されているすべての領収書を確認します
  • アプリは、バックグラウンドからの復帰などでサブスクリプション状態をバックエンドに照会します。

これは、サブスクリプションを処理するための唯一の正しい方法のように思えました。 また、しばらくの間、自動更新可能なサブスクリプションを商業的に使用している他の開発者とこのプロセスを検証しました。

したがって、OPの質問に対する私の答えは、フロントエンドではなくバックエンドで定期的にサブスクリプションを確認することです。

@schumannd

同じ問題を理解しているのか、話しているのかわかりません。

領収書の検証はサーバーで実行する必要があります。 Apple自身のドキュメントによると

アプリからAppStoreサーバーの/verifyReceiptエンドポイントを呼び出さないでください。

参照記事の「チート」は、バックエンドサーバーに委任するのではなく、簡潔にするために、サンプルアプリがアプリから直接/verifyReceipt直接呼び出すものとして具体的に解釈しました。

Apple / App Storeは、信頼できる唯一の情報源であり、そうあるべきだと私には思えます。 Appleは最終的に購入、更新、キャンセルなどを処理し、それに応じて領収書を生成し、そのデータをStoreKit APIを介して利用できるようにします。

react-native-iapは問題なく購入と購入の復元を処理しますが、ローカルでappStoreReceiptUrlで利用できるApp Storeのレシートデータへのアクセスにはまだギャップがあると思います。これも、 Appleが文書化したレシートへのアクセス方法です。データ

領収書データを取得するには、 NSBundleappStoreReceiptURLメソッドを使用して、アプリの領収書を見つけます...

Appleのドキュメントを読み、ネイティブのObject-C / Swift実装を参照することで理解できるワークフローは、次のとおりです。

  • 購入する製品をロードする
  • 製品を購入する(消耗品、非消耗品、サブスクリプション、関係ありません)
  • その購入の領収書は、舞台裏でappStoreReceiptUrlによってStoreKitローカルに保存されます
  • アプリは、必要に応じて検証のためにレシートデータをバックエンドサーバー(App Store /verifyReceipt直接送信しない)に送信する必要があります
  • appStoreReceiptUrlは、キャンセルや更新が発生するたびにStoreKitによって更新されます(適切なStoreKitデリゲートが正しく登録されていると仮定)
  • appStoreReceiptUrlがnullの場合、ユーザーが新しいデバイスを使用しているなどの理由で、Apple / AppStoreから現在のレシートデータを取得する購入復元ワークフローを使用すると、 StoreKitはこれをappStoreReceiptUrlローカルに保持します

繰り返しになりますが、 react-native-iapは、 appStoreReceiptUrlからの領収書データの読み込みを除いて、これらすべてを処理します。 ローカルレシートを照会するgetReceiptメソッドを使用すると、サブスクリプションやその他の購入を管理する負担が軽減されると思います。

Appleは、これを本来あるべきよりもはるかに推論するのを難しくしている。

appStoreReceiptUrlは、キャンセルや更新が発生するたびにStoreKitによって更新されます(適切なStoreKitデリゲートが正しく登録されていることを前提としています)

これは、私がこのアプローチで抱えている問題を説明しています。ユーザーがインターネット接続が機能している状態でアプリを後で開かない場合、更新/キャンセル/有効期限などの通知は届きません。

それ以外は、私が説明したアプローチの良い代替案のようです。 プロダクションアプリで最もよく使われているのはどれだろうか。

@sellmeadogそれは私がここに投稿したのと同じ考えだと思います:#356
レシートをローカルで検証することは1つの方法であり、アップルが推奨しています。 これは、サーバー/ネットワークの要求から完全に独立しています。

うん。 「ネットワーク接続がない-検証がない」という欠点があります。
しかし、そのユースケースがあります。
アプリを起動するたびにレシートをすばやく検証したいのですが、 UserDefaultsまたはKeychain介して自分でアプリ内購入を追跡したくありません。 StoreKitすでに保存メカニズムを提供しています。

getAvailablePurchasesなどを介してitunesアカウントにログインするように求めることなく、IOSユーザーがサブスクリプションを更新またはキャンセルしたかどうかをどのように確認する必要がありますか?

例えば:
サブスクリプションを最初に購入すると、レシートを検証し、有効期限をFirebaseプロファイルに保存します。 そのFirebaseノードを使用して、アクティブなサブスクリプションがあるかどうかを起動を確認します。 この問題は、その有効期限が過ぎて新しい請求期間が開始されたときに発生します。 自動更新またはキャンセルされたかどうかを確認するにはどうすればよいですか? 前述のように、getAvailablePurchasesを使用していましたが、復元ボタンのようにitunesのログインを促します。これはひどいUIです。

私も同じことだろうか。

私たちのアプリでは、ステータスを確認するためにAppleと直接通信するサーバー側APIがあるため、これは必要ありません。 最初の購入後、レシートデータはサーバーに保存され、後で更新されたステータスを要求するために使用されます。

ただし、これはデバイス側でも可能であると思います。 私はこれに関する専門家ではありませんが、私が理解しているように、アプリは更新が発生するたびにOSから更新されたトランザクション/レシートを受け取ります。 このプラグインは、アプリの起動時にこれらのレシートを処理していると思われます。 (Xcodeから実行すると、複数のトランザクションを処理しているように見える大量のログが表示されます)しかし、私が知る限り、JSコードでこれらのイベントを利用する方法はありません。

これについてもう少し情報を得ることができますか?

@csumrell @curiousdustin稼働環境でこの動作を確認しましたか? サンドボックスが原因で発生している可能性があるのではないかと思います。デバイスにはおそらく別の非サンドボックスアカウントがあるため、サンドボックスアカウントにサインインする必要がありますが、本番環境では、ユーザーはおそらく通常のアカウントにサインインします。モジュールは、ログインを要求せずにgetPurchasesを取得できる場合があります。

申し訳ありませんが、 getAvailablePurchases()が本番環境でパスワードプロンプトを表示することを確認していません。

私の経験では、少なくともiOSでは認証が含まれる、購入の復元と一般に呼ばれる機能に使用されているこの方法についてドキュメントが説明しているためだと思いました。

@hyochan @JJMoonこれについてももっと情報を

@curiousdustin yeaなので、通常のiTunesアカウントからサインアウトしてサンドボックスアカウントにサインアウトしても、このメソッドが呼び出されたときにログインを求めるプロンプトが表示されなくなりました。 したがって、私の推測/希望は、ユーザーが使用中のサンドボックスアカウントを持っていない本番環境では、問題が発生することはないはずです。 ベータテストは、ユーザーがデバイスにサンドボックスアカウントを設定していない本番環境と同じように機能するはずです。これは、開発デバイスの問題にすぎません。 だから私は明日ベータユーザーでこれをテストし、私が見つけたものをあなたに知らせます。
編集:これがサンドボックス以外のデバイスで発生することを確認できます。 これはひどいUXであり、非常に問題があります。 誰か、何かアイデアはありますか?

そのため、アプリからAppStoreサーバー/ verifyReceiptエンドポイントを呼び出して自分のサーバーで検証すると、元の最初の購入レシートだけで、そのユーザーの最新の更新日情報が常に返されます。

ローカルのvalidateメソッドを使用しても常に最新の情報が返されるかどうかを誰かが知っていますか? それとも、ローカルで検証するのはその領収書のためだけですか?

また、Appleで検証するために独自のサーバーを設定するためのアドバイスはありますか? 私はそれについての経験がありません

@csumrell getPurchaseHistoryを呼び出して並べ替えることで、最新の購入の領収書を取得できます。 上記のコメントは、これを行う方法を詳しく説明しています。 これには最新の情報が含まれているはずです。

そして、お互いに助け合うことができるように、サーバーで検証するオプションを検討しようとしています。 しかし、他の誰かがそれについてどのように行ったかを聞きたいです。

@kevinEsherickはい。ただし、getPurchaseHistoryはItunesログインポップアップをトリガーします。 ユーザーが最初に購入したときに、元のレシートをローカルストレージに保存することについて話しています。 次に、getPurchaseHistoryを呼び出して次の請求を確認する代わりに、ローカルで検証されたvalidateReceiptIos(originalReceipt)を呼び出します。 ただし、validateReceiptIosがアップルサーバー/ verifyReceiptのように最新のトランザクションを返すかどうかはわかりません

@csumrellガッチャ。 それはすばやく簡単にテストできます。 やってみませんか? そうでない場合は、今日後でチェックアウトします。
編集: @csumrell validateReceiptIosは実際、その購入の最新の自動更新を追跡するため、これは有効な方法です。 これは、iTunesのログインプロンプトを回避するため、サブスクリプションをチェックするための上記の提案された方法よりも優れていると思います(誰かがその修正を思い付くことができない限り)。 欠点は、領収書をローカルに保存する必要があることです。 これはそれほど面倒なことではありません。 また、セキュリティ上の理由や、大量の(〜60k文字)という事実のために、これらの領収書をバックエンドに送信したくない場合もあります。そのため、サブスクライブしたユーザーがサインアウトするか、新しいデバイスの使用を開始した場合は、次のことを行う必要があります。最新の購入レシートを取得するためにログインするように促します。 サブスクリプションステータスを内部に保存して、最後にチェックしたときにサブスクライブしたユーザーのみにプロンプ​​トを表示することができます。

@hyochanはこの問題に$ 20.00の資金を提供しました。 IssueHuntでご覧ください

@hyochanあなたはどのような具体的な解決策に資金を提供していますか? このスレッドでいくつか提供しましたが、私の最新のコメントは、これまでで最も強力な解決策であり、問​​題が最も少ないと思います。 これらのソリューションをREADMEの1つの簡潔なPRにまとめるために、誰かに資金を提供していますか? それとも、これはまだ解決したい実際のコードの問題がありますか?

@kevinEsherick

これらのソリューションをREADMEの1つの簡潔なPRにまとめるために、誰かに資金を提供していますか?

はい。 これは絶対に正しいです。 また、 issue huntが箱から出してどのように機能するかをテストしたかっただけです。 私の次の計画は、テストケースの作成に資金を提供することです。

@kevinEsherick正解です

この方法を使用して、独自のサーバーをセットアップする必要をなくし、サブスクリプションがアクティブかどうかを確認する際のitunesログインポップアップを回避します。

@csumrellと私がレイアウトしたこの検証フローの使用を検討している人への注意:開発中、最初の起動時にiTunesログインプロンプトがまだポップアップしていることがわかりました。 これは本番環境では発生しません。 あなたが私たちがレイアウトしたステップに従っている限り、すべてがうまくいくはずです。 これを行う理由については、iOSがIAPが使用されていることを確認した場合、または開発中のモジュールマップの一部である場合、自動的にサインインを促します。よくわかりませんが、サンドボックステストの機能にすぎないようです。

ねえ、最近この問題に関する活動はなかったようです。 問題は修正されましたか、それともコミュニティの注意が必要ですか? それ以上のアクティビティが発生しない場合、この問題は解決される可能性があります。 この問題に「ディスカッション用」または「良い最初の問題」というラベルを付けることもできます。開いたままにしておきます。 貢献していただきありがとうございます。

長期間使用されなかった後、この問題を解決します。 この問題が最新リリースでも引き続き発生する場合は、最新の情報を使用して新しい問題を作成してください。

おそらく、このフロー全体をドキュメントで明確にする必要がありますか?

特に自動更新サブスクリプションに関しては? サブスクリプションがまだアクティブであるかどうかについてexpires_date_msを確認できるかどうかは、初心者には非常に不明確ですか?

これに最適な場所は、より完全な実例にあると思いますか?

人々はこれに興味がありますか? 時間があれば、これに取り組むことができますか?

@alexpchinはい、それは間違いなくクリーンになります

同意! 誰かが#856に興味がありますか?

こんにちは、

@andrewzeyのメソッドは、サブスクリプションのレシートを突然検証できなくなった昨日まで、うまく機能していました

RN 0.61.4、RNIap:4.4.2、およびiOS13.3.1を実行しています

私たちは試しました:

  • アプリを再インストールします
  • 新しいユーザーアカウント
  • 新しいアプリの秘密を使用する
  • 各ユーザーのすべての領収書をテストします-単一の領収書を解析することはできません

サンドボックスを購入したときにfinishTransactionIOSを正しく使用していなかったかどうか疑問に思っていますか?

本当に奇妙なのは、このオンラインツールを使用してレシートを検証すると、すべてが正常に見え、すべてのレシートメタデータを確認できることです。

  isSubscriptionActive = async () => {
      const availablePurchases = await RNIap.getAvailablePurchases();
      const sortedAvailablePurchases = availablePurchases.sort(
        (a, b) => b.transactionDate - a.transactionDate
      );
      const latestAvailableReceipt = sortedAvailablePurchases[0].transactionReceipt;
      const isTestEnvironment = __DEV__;

      try {
        const decodedReceipt = await RNIap.validateReceiptIos(
          {
            'receipt-data': latestAvailableReceipt,
            password: Config.IN_APP_PURCHASE_SECRET,
          },
          isTestEnvironment
        );
        console.log('response!', decodedReceipt)
      } catch (error) {
        console.warn('Error validating receipt', error) // JSON PARSE ERROR HERE
      }
...

@andrewzeyが配置したコードに関する質問。 Date.now()が現在のデバイス時間ではなく、ユーザーがこれを変更して無限のサブスクリプションを持つ可能性がありますか? 🤔

また、アプリ自体からの領収書を確認することはお勧めできませんか?

@doteric彼らが落胆していると言っているところを教えて
Appleや他のSolidReactNativeソースから適切なドキュメントを見つけるのに苦労しています。

@doteric yes Date.now()はデバイス時間であるため、回避できます。 それでも、ユーザーがこれを行う可能性はごくわずかであり、他の方法でさえ、無限のサブスクリプションを回避することができます。 たとえば、単純なサーバー側の検証を使用する場合、アプリを開く前に機内モードに入り、アプリがサブスクリプションの有効期限が切れていることを認識しないようにすることができます。 もちろん、他にも保護策を講じることができますが、私のポイントは、Date.now()を使用するクライアント側は確かに機能しているということです。 @captaincole私は手元にドキュメントを持っていませんが、クライアント側の検証が推奨されていないことを私も読んだことを確認できます。 私はそれを私が信じるAppleドキュメントで読んだ。 そうは言っても、クライアント側が仕事を成し遂げると思います。

こんにちは、

私は、validateReceiptIosとlatest_receipt_data(expires_date_msと実際の日付を比較)を使用して、このスレッドで説明されているアプローチの1つを試していました。 Xcodeでの開発中にはうまく機能しました。 ただし、Testflightでテストしたところ、機能しなくなりました。 デバッグが難しいため、正確な問題を特定できません。レシートデータを取得していないようです。 誰かがtestflightで同様の問題を抱えていましたか?

前もって感謝します!

こんにちは、

私は、validateReceiptIosとlatest_receipt_data(expires_date_msと実際の日付を比較)を使用して、このスレッドで説明されているアプローチの1つを試していました。 Xcodeでの開発中にはうまく機能しました。 ただし、Testflightでテストしたところ、機能しなくなりました。 デバッグが難しいため、正確な問題を特定できません。レシートデータを取得していないようです。 誰かがtestflightで同様の問題を抱えていましたか?

前もって感謝します!

+1

@asobralr @ Somnus007私は間違っているかもしれませんが、ユーザーはtestflightで購入できないため、testflightでIAPをテストできるとは思いません。 Appleは、本番環境のような環境で購入をテストするための素晴らしい機会を提供していません

@asobralr @ Somnus007私は間違っているかもしれませんが、ユーザーはtestflightで購入できないため、testflightでIAPをテストできるとは思いません。 Appleは、本番環境のような環境で購入をテストするための素晴らしい機会を提供していません

正しい。 残念なことに、サンドボックスで障害シナリオをシミュレートすることさえできません。 😞

こんにちは@kevinEsherick 、お返事ありがとうgetPurchaseHistory

requestSubscription()を呼び出す前にgetAvailablePurchases()を呼び出すと問題が発生するため、iOS14はこのソリューションを破っているようです。

このページは役に立ちましたか?
0 / 5 - 0 評価