4.4.6
0.61.5
iOS
purchaseUpdatedListener
requestSubscription
ํตํ ํ ๋งค๋ฒ purchaseUpdatedListener
requestSubscription
ํตํ
purchaseUpdatedListener๋ ์ฑ ์์์ ํ ๋ฒ๋ง ํธ์ถ๋๊ณ requestSubscription ํธ์ถ ํ์๋ ํธ์ถ๋์ง ์์ต๋๋ค.
์ค์ ์ฅ์น
readme๋ฅผ ๋ฐ๋ฅด๊ณ ๊ตฌ๋ ์ ์์ฒญํ์ญ์์ค.
๋ค๋ฅธ ์ฌ๋๋ ๊ฐ์ ๋ฌธ์ ๊ฐ ์์ต๋๊น? @Strate finishTransaction
ํ์ต๋๊น?
@hyochan ์,ํ์ง๋ง ์ค์ ๋ก์ด ํธ์ถ์ ์ฑ์ ๋ค์ ์์ํ ํ์ ๋ฐ์ํฉ๋๋ค.
@hyochan ์ ๋ expo-in-app-purchase ํจํค์ง๋ฅผ ์ฌ์ฉํด ๋ณด์์ง๋ง ์ด์ ๊ฐ์ ๋ฌธ์ ๋ ์์ต๋๋ค.
@Strate ๊ทํ์ ์ฝ๋๋ฅผ๋ณด๊ณ ์ถ์ต๋๋ค. ์ง์ ์ค๋ฅ๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.
์ด ๋ฌธ์ ๋ ์ ๋์ ์ผ๋ก ํ๊ฐ๋ฉ๋๋ค. ๊ทธ๋ ์ง ์์ ์ด์ ๋ฒ์ ์ด ์์ต๋๊น?
๋ค๋ฅธ ์ฌ๋๋ ๊ฐ์ ๋ฌธ์ ๊ฐ ์์ต๋๊น? @Strate
finishTransaction
ํ์ต๋๊น?
๊ตฌ๋งค๊ฐ finishTransaction์ ์ธ์์ด๊ธฐ ๋๋ฌธ์ ์ด๋ป๊ฒ ๊ฐ๋ฅํ ๊น์? ๋ฐ๋ผ์ finishTransaction์ ์ ๋ฌํ ์ธ์๋ฅผ ๊ฐ์ ธ ์ค๋ ค๋ฉด ์ด๋ฒคํธ ๋ฆฌ์ค๋๊ฐ ํ์ํฉ๋๋ค.
@Sophrinix finishTransaction์ด purchaseUpdatedListener
๋ด๋ถ์์ ํธ์ถ ๋ ๊ฒ์ผ๋ก ์์๋ฉ๋๋ค.
@hyochan ์ฃ์กํ์ง๋ง ์ง๊ธ์ ์ค์ ์ฝ๋๊ฐ์๋ ๊ฒ ๊ฐ์ต๋๋ค. expo-in-app-purchase
๋ชจ๋๋ก ์ ํํ์ต๋๋ค. @Sophrinix ๊ฐ ๋์ผํ ๋ฌธ์ ๋ฅผ ๊ฒฝํ ํ ๊ฒ ๊ฐ์ต๋๋ค.
Btw, ๋ด ์ฝ๋์๋ ํน๋ณํ ๊ฒ์ด ์์์ต๋๋ค. ์ฑ์ด ์์ ๋ ์๋ง์ ๋ฆฌ์ค๋๋ฅผ ๋ฑ๋กํ๊ณ readme๋ฅผ ๋ฐ๋ฅด์ญ์์ค.
์ด๊ฒ์ ํ๊ท๋ผ๋ ๊ฒ์ด ๋ฐํ์ก์ต๋๋ค.
๋ค์ ๋ฒ์ ์ ์ฌ์ฉํ๋ฉด ๋ชจ๋ ๊ฒ์ด ์๋ํฉ๋๋ค.
"react": "16.8.1",
"react-native": "^0.59.10",
"react-native-iap": "4.3.0",
์ฌ์ฉํ๋ ค๊ณ ํ ๋ ๋ฌธ์ ๋ ์จ๋ค react-native-iap
4.4.4
์ ๋ฒ์ react-native
์ด์ ์ 0.60
@Sophrinix ๋ฐฉ๊ธ ๋ด ํธ์์ requestPurchase
์๋ํ๋๋ฐ ๋ชจ๋ ๊ฒ์ด ์๋ํ๋ ๊ฒ ๊ฐ์ต๋๋ค. ์ฝ๋๋ฅผ ๊ณต์ ํด ์ฃผ์๊ฒ ์ต๋๊น?
๋ํ initConnection
์ ํ๋ฅผํ๋์ง ๋ค์ ํ์ธํ์๊ธฐ ๋ฐ๋๋๋ค. ์ด๋ android
์์์ ๊ฐ์ด iOS
์์ ํธ์ถํด์ผํ๋ ์ต๊ทผ ์
๋ฐ์ดํธ์ ์ค์ํ ๋ณ๊ฒฝ ์ฌํญ์
๋๋ค.
4.3.0์ผ๋ก ๋ ๋๋ฆฌ๋ ๊ฒ์ด ์๋ ํจ์ ํ์ธํฉ๋๋ค. ๋๋ ์ต์ ๋ฒ์ ์ผ๋ก ๋ฏธ์ณ ๊ฐ๊ณ ์์๊ณ ๋ฌธ์ ๋ฅผ ์ฐพ์ผ๋ ค๊ณ 1 ์๊ฐ ์ด์ ๋๋ฒ๊น ํ์ต๋๋ค.
4.3.4
์์ 4.4.3
๊น์ง ์ถ๊ฐํ๋ฉด ๋ฌธ์ ๊ฐ 4.4.4
์์ ์์๋ฉ๋๋ค.
4.3.4
์์4.4.3
๊น์ง ์ถ๊ฐํ๋ฉด ๋ฌธ์ ๊ฐ4.4.4
์์ ์์๋ฉ๋๋ค.
์ฌ๊ธฐ์๋ 4.4.8์์ 4.4.3์ผ๋ก ๋ค์ด ๊ทธ๋ ์ด๋๋์์ผ๋ฉฐ ํ์ฌ ์๋ ์ค์ ๋๋ค!
๋ค๋ฅธ ์ฌ๋๋ ๊ฐ์ ๋ฌธ์ ๊ฐ ์์ต๋๊น? @Strate
finishTransaction
ํ์ต๋๊น?
๋๋์ ๋์ผํ ๋ฌธ์ ๊ฐ ์ค์ 4.4.0
ํธ์ถ๋๋ ์ด๋ฒคํธ ๋ฆฌ์ค๋์ ๊ฒ๋ ํฌํจ - purchaseErrorSubscription
.
๋ค์ด ๊ทธ๋ ์ด๋์ ๋ํด ์ฝ์ด๋ณด์ญ์์ค. ์๋ํด ๋ณด๊ฒ ์ต๋๋ค.
ํธ์ง : ๋ค์๊ณผ ๊ฐ์ ์ด์ ๋ก ์ฌ๊ฐํ ๋ฌธ์ ์ ๋๋ค.
4.3.0
์ด ์๋ํ๋์ง ํ์ธํ ์๋ ์์ต๋๋ค.
RN 0.62.2 ๋ฐ react-native-iap 4.4.8์์ ๋ฉฐ์น ๋์ ๋์ผํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.
README์ ์์ ์์ ๋๋ฝ ๋์๊ธฐ ๋๋ฌธ์ initConnection()
๋์ณค์ต๋๋ค.
4.4.8๋ก ์ ๊ทธ๋ ์ด๋ ํ ๋ iOS์์ ๋์ผํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ฌ ์ผ๋ถ ๊ตฌ๋ ์ด ์๋ฃ๋์ง ์์์ต๋๋ค. 4.4.3์ผ๋ก ๋ค์ด ๊ทธ๋ ์ด๋ํ๋ฉด ํ์ฌ ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋์์ต๋๋ค. initConnection ()์ ํ์์ ๋๊น? ์์ฌ๋ ๊ทธ๋ ์ง ์์ ๊ฒ์ฒ๋ผ ๋ณด์ ๋๋ค.
initConnection()
์ ํ๋ฅผ ์ถ๊ฐํ์ง ์์ ๊ฒ๊ณผ ๋์ผํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.
README๋ ์ฌ๊ธฐ์ ๊ตต์ ๋ถ๋ถ์ผ๋ก ์
๋ฐ์ดํธ ๋ ๊ฒ ๊ฐ์ต๋๋ค.
initConnection()
iOS์์๋ canMakePayments ๋ฉ์๋๋ฅผ ํธ์ถํ๊ณ ๋ฆฌ์ค๋๊ฐ ์ ๋๋ก ์๋ํ๋ ๋ฐ ํ์ํ __ ๊ฐ์ ๋ฐํํฉ๋๋ค .__
"iOS์์๋ canMakePayments๋ฅผ ํธ์ถํ๊ธฐ ๋งํ๋ฉด๋ฉ๋๋ค."์ด ๋ถ๋ถ์ ์ ๊ฑฐํ๊ณ ๊ธฐ๋ณธ ์์ ์ initConnection()
๋ ์ถ๊ฐํด์ผํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
๋๋ ๊ทธ๊ฒ์ด ์์ ์ ์์๊ธฐ ๋๋ฌธ์ ๊ทธ๊ฒ์ด ์ ํ ์ฌํญ์ด๋ผ๊ณ ์ ๋ง๋ก ํ์ ํ์ต๋๋ค.
๊ตฌ๋งค ๋ฆฌ์ค๋๋ฅผ ๋ฑ๋กํ๊ธฐ ์ ์ initConnection()
๋ฅผ ์ถ๊ฐํ๋ฉด์ด ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋์์ผ๋ฏ๋ก # 1002 ๋ฐ # 756๊ณผ ๊ด๋ จ์ด์์ ์ ์์ต๋๋ค.
๋๋ 4.4.9๋ฅผ ์ฌ์ฉํ๊ณ ์์ผ๋ฉฐ์ด ํฐ์ผ์ ์ค๋ช
๋ ๋ฌธ์ ๋ ๋์๊ฒ ๋ฐ์ํ๊ณ ์์ต๋๋ค.
๋ฆฌ์ค๋๋ ์์๋ ๋๋ง ํธ์ถ๋์ง๋ง ๋ด๊ฐ ์ค์ ํ ๋ค์ ๊ตฌ๋งค๋ฅผ ์ํํ๋ฉด ํธ์ถ๋์ง ์์ต๋๋ค.
react-native-iap/index.ts
๋ณด๊ณ ๋ด๋ถ์์ ์ผ์ด๋๋ ์ผ์ ํ์
ํ ํ ๋ค์ดํฐ๋ธ ์ด๋ฒคํธ๋ฅผ ์ง์ ๊ตฌ๋
ํ์ฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ต๋๋ค.
์ด๋ ์ธ์ ๋ ์ง ์ํ ํ ์ ์์ผ๋ฉฐ ์ง์๋ฉ๋๋ค. (ํ ๋ฒ๋ง ์๋ฃ๋์๋์ง ํ์ธํ์ญ์์ค)
import { NativeModules, NativeEventEmitter } from 'react-native';
import { Observable } from 'rxjs/Observable';
const purchaseEvent = Observable.fromEvent(
new NativeEventEmitter(NativeModules.RNIapIos),
'purchase-updated'
);
const purchaseSubscription = purchaseEvent.subscribe((transactionData) => {
// Trigger server receipt validation here...
});
const errorEvent = Observable.fromEvent(
new NativeEventEmitter(NativeModules.RNIapIos),
'purchase-error'
);
const errorSubscription = errorEvent.subscribe((errorData) => {
// Handle errors here...
});
initConnection()
๊ฐ README์ ์์ ์ฝ๋์ ์๊ธฐ ๋๋ฌธ์ ๋ง์ ์ฌ๋๋ค์ด ์ค๋ฅ๋ฅผ ๊ฒช๊ณ ์์ต๋๋ค. ์ฌ๊ธฐ์ ์ถ๊ฐํ์ต๋๋ค : # 1088,ํ์ง๋ง ๋๊ตฐ๊ฐ ๋ด ์ฝ๋๋ฅผ ๋ค์ ํ์ธํ ์ ์๋ค๋ฉด ๊ฐ์ฌํ๊ฒ ์ต๋๋ค. (๋๋ ์ฌ์ ํ ๋ด ์ฝ๋๊ฐ ์์ ํ ์๋ํ์ง ์์ผ๋ฏ๋ก ๊ทธ๊ฒ์ ๋ํด ๋๋ฌด ํ์ ํ์ง ์์ต๋๋ค ...)
v5.1.1์์๋์ด ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค. initConnection
ํด๊ฒฐ๋์ง ์์์ต๋๋ค. ๋ฆฌ์ค๋ ์ฝ๋ฐฑ์ purchaseUpdate์์ ํธ๋ฆฌ๊ฑฐ๋์ง ์์ต๋๋ค. ๊ทธ๋๋ ์๋๋ก์ด๋์์๋ ์ ์๋ํฉ๋๋ค. ๋ด ํด๊ฒฐ ๋ฐฉ๋ฒ์ @mrozanski ์ ๊ฐ์ Observables๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์
๋๋ค.
import React, { useContext, useEffect, useState } from 'react';
import { Alert, EmitterSubscription, Platform, NativeEventEmitter,
NativeModules } from 'react-native';
import { connect } from 'react-redux';
import RNIap, {
InAppPurchase,
PurchaseError,
SubscriptionPurchase,
purchaseErrorListener,
purchaseUpdatedListener,
} from 'react-native-iap';
import { Observable, Subscription } from 'rxjs';
const RNIAPEvent = new NativeEventEmitter(NativeModules.RNIapIos);
const purchaseObservable = new Observable((subscriber) => {
RNIAPEvent.addListener('purchase-updated', (event) => {
subscriber.next(event);
})
})
const RNIAPErrorEvent = new NativeEventEmitter(NativeModules.RNIapIos);
const purchaseErrorObservable = new Observable((subscriber) => {
RNIAPErrorEvent.addListener('purchase-error', (event) => {
subscriber.next(event);
})
})
const Wrapper = ({ ...props }) => {
let purchaseUpdateSubscription: EmitterSubscription | Subscription | null = null;
let purchaseErrorSubscription: EmitterSubscription | Subscription | null = null;
const validateTransaction = async (purchase: SubscriptionPurchase) => {
return new Promise(async (resolve) => {
//resolve(validationResponseFromYourBackend)
}
}
const handleSubEvent = async (purchase: InAppPurchase | SubscriptionPurchase) => {
const receipt = purchase.transactionReceipt;
const purchaseToken = purchase.purchaseToken
if (receipt) {
try {
const result = await validateTransaction(purchase);
if (result.status === 200) {
RNIap.acknowledgePurchaseAndroid(purchaseToken).then(() => {
RNIap.finishTransaction(purchase, false)
.then(() => giveYourUserValue())
.catch((e) => {
//
})
})
}
} catch (err) {
//
}
}
}
useEffect(() => {
RNIap.initConnection()
.then(() => {
RNIap.flushFailedPurchasesCachedAsPendingAndroid().catch(() => {
// exception
})
.then(() => {
if (Platform.OS === 'ios') {
//Documented implementation has issues purchaseUpdatedListener callback
purchaseUpdateSubscription = purchaseObservable.subscribe((purchase) => {
console.log('purchase observable', purchase)
handleSubEvent(purchase);
});
purchaseErrorSubscription = purchaseErrorObservable.subscribe((error) => {
console.log('purchaseErrorListener', error);
})
} else {
//for android use the documented method. Callbacks work.
purchaseUpdateSubscription = purchaseUpdatedListener(
(purchase: InAppPurchase | SubscriptionPurchase) => {
handleSubEvent(purchase);
}
);
purchaseErrorSubscription = purchaseErrorListener(
(error: PurchaseError) => {
console.log('purchaseErrorListener', error);
},
);
}
})
})
return () => {
// clear your listeners
//eg if Subscription purchaseErrorSubscription.unsubscribe()
//eg if EmitterSubscription purchaseErrorSubscription.remove()
}
}, []);
return (
<InAppSubContext.Provider
value={{
someValueYouWantPassedDown: 'theValue'
}}
>
{props.children}
</InAppSubContext.Provider>
)
}
const mapState = (state) => ({ someProps: 'yeah' });
const InAppSubscriptionManager = connect(mapState)(Wrapper);
export default InAppSubscriptionManager;
์ด์ ์ด๊ฒ์ ์ฌ์ฉํ์ฌ App.tsx
์ฑ์ ๋ํ ํ ์ ์์ต๋๋ค.
import InAppSubscriptionManager from './path/to/inAppSubscriptionManager';
const App = () => {
return (
<Provider store={store}>
<InAppSubscriptionManager>
<AppNavigator />
</InAppSubscriptionManager>
</Provider>
);
}
export default App;
๋์์ด๋์ด ๋คํ์
๋๋ค. ์ฐ๋ฆฌ๋ 6 ์๋ถํฐ ์ด๊ฒ์ ์์ฐํ๊ณ ์์ต๋๋ค.
์ด๋ ์์ ์์ Observable์์ ์ด๊ฒ์ผ๋ก ๋ณ๊ฒฝ๋์์ต๋๋ค (์ฐ๋ฆฌ๋ typescript๋ฅผ ์ฌ์ฉํ์ง ์์ต๋๋ค)
const purchaseEvent = new NativeEventEmitter(NativeModules.RNIapIos);
const subscription = purchaseEvent.addListener(
'purchase-updated',
transactionData => {
console.log('IAP-LOG purchase-updated');
dispatch(validateRecepit(transactionData));
}
);
const errorSubscription = purchaseEvent.addListener(
'purchase-error',
data => {
crashlytics().log(`Purchase error ${JSON.stringify(data)}`);
console.log('IAP-LOG purchase-error', data);
}
);
};
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
initConnection()
์ ํ๋ฅผ ์ถ๊ฐํ์ง ์์ ๊ฒ๊ณผ ๋์ผํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.README๋ ์ฌ๊ธฐ์ ๊ตต์ ๋ถ๋ถ์ผ๋ก ์ ๋ฐ์ดํธ ๋ ๊ฒ ๊ฐ์ต๋๋ค.
"iOS์์๋ canMakePayments๋ฅผ ํธ์ถํ๊ธฐ ๋งํ๋ฉด๋ฉ๋๋ค."์ด ๋ถ๋ถ์ ์ ๊ฑฐํ๊ณ ๊ธฐ๋ณธ ์์ ์
initConnection()
๋ ์ถ๊ฐํด์ผํ๋ค๊ณ ์๊ฐํฉ๋๋ค.๋๋ ๊ทธ๊ฒ์ด ์์ ์ ์์๊ธฐ ๋๋ฌธ์ ๊ทธ๊ฒ์ด ์ ํ ์ฌํญ์ด๋ผ๊ณ ์ ๋ง๋ก ํ์ ํ์ต๋๋ค.
๊ตฌ๋งค ๋ฆฌ์ค๋๋ฅผ ๋ฑ๋กํ๊ธฐ ์ ์
initConnection()
๋ฅผ ์ถ๊ฐํ๋ฉด์ด ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋์์ผ๋ฏ๋ก # 1002 ๋ฐ # 756๊ณผ ๊ด๋ จ์ด์์ ์ ์์ต๋๋ค.