This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useState, useEffect } from 'react'; | |
import { Platform } from 'react-native'; | |
import * as InAppPurchases from 'expo-in-app-purchases'; | |
import * as Sentry from '@sentry/react-native'; | |
const IAP_SKUS = Platform.select({ | |
ios: [ | |
'your_sku_alias', | |
], | |
android: [ | |
'your_sku_alias', | |
], | |
}); | |
export const IAPContext: React.Context<any> = React.createContext({ | |
processing: false, | |
setProcessing: () => undefined, | |
getProducts: () => undefined, | |
}); | |
export const useIap = (): void => React.useContext(IAPContext); | |
export const IAPManager = (props: any): JSX.Element => { | |
const [processing, setProcessing] = useState(false); | |
const processNewPurchase = async (purchase: InAppPurchases.InAppPurchase): Promise<void> => { | |
const { productId } = purchase; | |
// iOS | |
if (Platform.OS === 'ios') { | |
if (purchase.transactionReceipt) { | |
// ここにアイテム購入後のアプリ側の処理を書く(iOS) | |
} | |
} | |
// Android | |
if (Platform.OS === 'android') { | |
if (purchase.purchaseToken && productId) { | |
// ここにアイテム購入後のアプリ側の処理を書く(Android) | |
} | |
} | |
try { | |
// 購入後の処理 | |
} catch (e) { | |
// 購入処理に失敗 | |
setProcessing(false); | |
} | |
}; | |
// 課金アイテムを取得 | |
const getProducts = async (): Promise<InAppPurchases.IAPItemDetails[] | undefined> => { | |
const { responseCode, results } = await InAppPurchases.getProductsAsync(IAP_SKUS as string[]); | |
if (responseCode === InAppPurchases.IAPResponseCode.OK) { | |
return results; | |
} | |
return []; | |
}; | |
// 初期化とリスナーの作成 | |
const initIAPandEventListeners = async (): Promise<void> => { | |
try { | |
await InAppPurchases.connectAsync(); | |
} catch (e) { /* すでにストアに接続されている場合 */ } | |
// 購入リスナー | |
InAppPurchases.setPurchaseListener(async ({ responseCode, results, errorCode }) => { | |
if (responseCode === InAppPurchases.IAPResponseCode.OK) { | |
if (results === undefined) return; | |
// 購入成功 | |
await Promise.all( | |
results.map(async (purchase) => { | |
await processNewPurchase(purchase); | |
InAppPurchases.finishTransactionAsync(purchase, true); | |
}), | |
); | |
} else if (responseCode === InAppPurchases.IAPResponseCode.USER_CANCELED) { | |
Sentry.captureMessage('ユーザーがトランザクションを途中キャンセルしました', Sentry.Severity.Log); | |
} else if (responseCode === InAppPurchases.IAPResponseCode.DEFERRED) { | |
// iOSのみ | |
Sentry.captureMessage('保護者の承認が必要です', Sentry.Severity.Log); | |
} else { | |
Sentry.captureMessage(`購入中にエラーが発生しました エラーコード: ${errorCode}`, Sentry.Severity.Log); | |
} | |
setProcessing(false); | |
}); | |
}; | |
useEffect(() => { | |
initIAPandEventListeners(); | |
}, []); | |
const { children } = props; | |
return ( | |
<IAPContext.Provider value={{ | |
processing, | |
setProcessing, | |
getProducts, | |
}} | |
> | |
{children} | |
</IAPContext.Provider> | |
); | |
}; | |
export default IAPManager; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment