"react-native-iap": "^ 2.3.25"
"๋ฐ์ ๋ค์ดํฐ๋ธ": "0.57.4",
IOS
buyProduct๋ promise๋ฅผ ๋ฐํํด์ผํฉ๋๋ค (.then () is not call),
buyProduct๊ฐ ์ฝ์์ ๋ฐํํ์ง ์๊ณ , Android์์๋ ์ ์๋ํ๊ณ .then () ํธ์ถ์ด ์ฑ๊ณต์ ์ผ๋ก ์ํ๋์์ง๋ง ios์์๋ ๊ทธ๋ ์ง ์์ต๋๋ค.
์ค์ ์ฅ์น
onBuyNowPress() {
this.setState({ loading: true });
RNIap.getProducts(['product_id']).then(success => {
RNIap.buyProduct('product_id').then(purchase => {
console.log("Purchase >>", purchase)
this.setState({
loading: false,
receipt: purchase.transactionReceipt,
});
Alert.alert('Purchase Successful!');
this.props.getPurchase();
}).catch(err => {
console.log(err.code, err.message);
this.setState({ loading: false });
Alert.alert(err.message);
if(err.message === "You already own this item.") {
this.props.getPurchase();
}
})
}).catch(error => {
alert(error);
this.setState({ loading: false });
})
}
iOS์์๋ ์ด๋ฏธ ์ ํ์ ๊ตฌ๋งค ํ์ผ๋ฏ๋ก ์ง๊ธ ๊ตฌ๋งค๋ฅผ ๋๋ฅด๋ฉด ์ด๋ฏธ์ด ์ ํ์ ๊ตฌ๋งค ํ ๊ฒ์ฒ๋ผ ํ์ ์ด ๋ํ๋ฉ๋๋ค. ํ์ง๋ง .then () ๋๋ .catch () ๊ฐ ์ ํ๋ฅผ๋ฐ์ง ์์ต๋๋ค.
๋๋ ๋ํ getAvailablePurchases () ๋ฉ์๋๋ฅผ ์๋ํ์ง๋ง ํญ์ []์ ๋ฐํํฉ๋๋ค
@LinusU @JJMoon ์ด ๋ง์๋ค ๊ณ ์๊ฐํฉ๋๋ค. async
๋ชจ๋ ์ ๊ฑฐํ๋๋ฐ ๋ฌธ์ ๊ฐ ๋ค์ ๋ฐ์ํฉ๋๋ค. ์ด๋ป๊ฒ ์๊ฐํด? @ ZeroCool00 ๋น๋ถ๊ฐ 2.3.24
๋ก ๋ค์ด ๊ทธ๋ ์ด๋ ํ์๊ฒ ์ต๋๊น?
@ ZeroCool00 ์ฌ์ค 2.3.26
์ฌ์ฉํด ์ฃผ์๊ฒ ์ต๋๊น?
@hyochan ์กฐ๋ง๊ฐ ํ ์คํธ ํ ๊ฒ์ .. ์๋ ค ๋๋ฆด๊ฒ์. ๋น ๋ฅธ ๋ต๋ณ ๊ฐ์ฌํฉ๋๋ค.
@hyochan 2.3.26์ผ๋ก ์๋ํ์ง๋ง ์๋ํ์ง ์์ต๋๊น? ์ด๋ค ํด๊ฒฐ์ฑ ?
@ ZeroCool00 ๊ทธ๋ ๋ค๋ฉด ์ฐ๊ฒฐ ๋ฌธ์ ์ผ ๊ฒ์
๋๋ค. unlink
์๋ํ๊ณ ๋ค์ link
์๋ํด์ผํฉ๋๋ค.
@hyochan ๋ด๊ฐ ์๋ํ์ง๋ง ๋งํฌ๋ฅผ ํด์ ํ๊ณ ์ ๊ฑฐํ๊ณ ๋ค์ ์ค์นํ๊ณ ๋ค์ ์ฐ๊ฒฐํฉ๋๋ค. ํ์ง๋ง ์ฌ์ ํ ์๋ํ์ง ์์ต๋๋ค
@ ZeroCool00 ์ฐฝ์ ์๋ค๋ฉด ๋ฐ์ ๋ค์ดํฐ๋ธ ๋งํฌ ์คํฌ๋ฆฝํธ๊ฐ ๋์ฑ ๋ถ์์ ํฉ๋๋ค. ์๋์ผ๋ก ์๋ ํ์ต๋๊น? ๋ํ 2.3.24
๋ ์๋ํ์ญ์์ค. ๊ตฌ์ฑ ๋ฌธ์ ์ ์ง๋ฉดํ๊ณ ์๋ค๊ณ ์๊ฐํฉ๋๋ค.
@hyochan im Mac์์ ์ฐ๊ฒฐ์ ํด์ ํ๊ณ 2.3.24๋ฅผ ์ ๊ฑฐํ ๋ค์ ์ค์นํ๊ณ ์๋ ์ค์ ์ ์ํํ๊ณ ๊ฐ ๋จ๊ณ๋ฅผ ์ํํ๊ณ Android์์ ์๋ํ๋ฉฐ ios์์๋ ์ฌ์ ํ ํ์๋์ง ์์ต๋๋ค. ํ๋ก์ธ์ค๊ฐ ์ ์๋ํฉ๋๋ค. ๋ฉ์ ์ ํ์ ๋ฐ ์ ํ ๊ตฌ๋งค๋ ๋ฐ๊ณ ์์ง๋ง ๋ฐํ ์ฝ์์ ์์ต๋๋ค.?
iOS์ ๋ํ ๋ค๋ฅธ ๊ตฌ์ฑ์ด ์์ต๋๊น? ์ฌ๊ธฐ์ ๊ฐํ์ ์ด๋ฏธ ๊ตฌ๋งค ํ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ด ์์ต๋๊น?
@JJMoon @ ZeroCool00 ๋์
@ ZeroCool00 ๋ํ Alert
์ ๊ฑฐํ๊ณ console
๋ฅผ ์ฌ์ฉํ์ฌ ๋์ ํ
์คํธํ์ญ์์ค. ios
๋ ๊ตฌ๋งค๊ฐ ์ฒ๋ฆฌ ๋ ๋ ์๋์ผ๋ก ๋ค์ดํฐ๋ธ Alert
์์ฑํ๊ธฐ ๋๋ฌธ์ ์ฝ๋๊ฐ ์ค๋จ ๋ ์ ์์ต๋๋ค.
@hyochan Plz๋ ์ด๊ฒ์ ๋ค์ ์ฝ๋ ๋ค .. ๋๋ ๋ชจ๋ ๊ฒ์ ์๋ํ๋ค .. ๋๋ ๋ํ ๊ฒฝ๊ณ ๋ฅผ ์ ๊ฑฐํ๋ค. ์ฌ์ง์ด ๋ ๋๋ฒ๊น ์ ์ค์งํ๊ณ ํ์ธํฉ๋๋ค .. ์๋ํ์ง ์์ต๋๋ค. ๋ด ์ฑ์ ๊ฒ์ํ๊ณ ์ถ์์ง๋ง ์ฌ๊ธฐ์ ๊ฐํ ์์ต๋๋ค. ๋๋ ์ฌ์ง์ด์ด lib https://github.com/chirag04/react-native-in-app-utils ์๋ํ์ต๋๋ค.
์ด lib๋ ๊ฐ์ ๋ฌธ์ ๊ฐ ์์ต๋๋ค. ๊ตฌ๋งค ํ๋ก์ธ์ค๊ฐ ์ ์๋ํ์ง๋ง ์ฝ์์ ์ป์ง ๋ชปํ์ต๋๋ค.
์ด๋ฒคํธ ์ฝ๋ฐฑ์๋ฐ๋ ์๋ช ์ฃผ๊ธฐ ๋ฉ์๋๊ฐ ์์ต๋๊น? ์๋ฒ API๋ฅผ ํธ์ถ ํ ์์๋ ์ด๋ฒคํธ ์ฝ๋ฐฑ์ ์ํฉ๋๋ค.
@ ZeroCool00 async
๋ฐ await
๋ ์ฌ์ฉํด ์ฃผ์๊ฒ ์ต๋๊น? ๋๋ ๋ํ ์ฐ๋ฆฌ ์ฑ์์ ์ด๊ฒ์ ์ฌ์ฉํ๊ณ ์์ผ๋ฉฐ ์ฐ๋ฆฌ๋์ด ๋ฌธ์ ์ ์ง๋ฉดํ์ง ์์ต๋๋ค.
@hyochan ์ด ๋ฐ๋ชจ๋ฅผ ์ ๊ณตํด ์ฃผ ๊ณ์ญ๋๊น .. ํฐ ๋์์ด ๋ ๊ฒ์ ๋๋ค.
async forIOS() {
let purchase = await RNIap.buyProduct('product_id');
console.log("BannerPurchase >>",purchase); **<--- THIS IS NOT GETTING CALL**
if(purchase) {
console.log("Purchase >>", purchase)
this.props.getPurchase();
this.setState({
loading: false,
receipt: purchase.transactionReceipt,
});
console.log('Purchase succesfully')
}
}
@hyochan ๋๋ ๋น์ ์ด ๋งํ๋ ๊ฒ์ ๋ฐ๋ฅด๊ณ ,์ด ๊ณผ์ ์ ๋ฌดํํ๋ฉฐ ์๋ฌด๊ฒ๋ ๋ฐํํ์ง ์๋ ๊ฒ ๊ฐ์ต๋๋ค. ๋๋ ์ฌ์ง์ด ๋ก๊ทธ๋ฅผ ์ป์ง ๋ชปํ๋ค.
์์ฆ ๋ง์ ์ฌ๋๋ค์ด ์ฐ๋ฆฌ ๋ชจ๋์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ๊ทํ์ ์ฌ๋ก๋ ๋งค์ฐ ์ด์ํด ๋ณด์ ๋๋ค. ์ฐ๋ฆฌ๊ฐ ๋น์ ์ ์์ ํ ์์ ์ฝ๋๋ฅผ ๊ฐ์ง๊ณ ์์ง ์์ผ๋ฉด ์ฐ๋ฆฌ๊ฐ ์์๋ด๋ ๊ฒ์ด ์ด๋ ค์ธ ๊ฒ์ ๋๋ค.
@hyochan @ ZeroCool00๊ณผ ๊ฐ์ ๋ฌธ์ ๊ฐ ์์ต๋๋ค.
2.3.26์์ 2.4.0-beta3์ผ๋ก ์
๊ทธ๋ ์ด๋ (์ฐ๊ฒฐ ํด์ ๋ฐ ์ฐ๊ฒฐ๋จ), ๊ฐ์ ์ด์ผ๊ธฐ์
๋๋ค.
์ฅ์น์์ ๋ก๊ทธ๋ฅผ ๊ฐ์ ธ์ต๋๋ค. ์ค์ iPhone์ ์ฌ์ฉํ์ฌ xCode (์์ด์ด ์ฐ๊ฒฐ)๋ฅผ ํตํ ๊ฐ๋ฐ ๋น๋.
[IAPInfoManager]: Update operation failed, error: Error Domain=SSErrorDomain Code=109 "Cannot connect to iTunes Store" UserInfo={NSLocalizedDescription=Cannot connect to iTunes Store, SSErrorHTTPStatusCodeKey=401}
๊ทธ๋ฌ๋ ๊ตฌ๋งค ํ์
์ด ์ฑ๊ณต ์ฌ๋ก์ ํจ๊ป ํ์๋ฉ๋๋ค. ๊ทธ๋ฌ๋ Javascript Thread์์ ๋ฐ์์ด ์์ต๋๋ค.
Promise๋ iOS ๋ชจ๋์์ ํด๊ฒฐ๋๊ฑฐ๋ ๊ฑฐ๋ถ๋์ง ์์ต๋๋ค.
try {
let purchase = false;
console.log('BEFORE BUY');
if (Platform.OS === 'ios') {
purchase = await RNIap.buyProduct(selected);
} else {
purchase = await RNIap.buySubscription(selected);
}
console.log('AFTER BUY');
await RNIap.finishTransaction();
console.info('purchase >', purchase);
setSubscription({type: selected, purchaseData: purchase});
} catch (err) {
console.log(err); // TODO add something went wrong
}
AFTER BUY
๋ํ๋์ง ๋ง. async / await์์ด .then
promise๋ฅผ ํด๊ฒฐํ๋ ๋์ผํ ์คํ ๋ฆฌ.
์ด ๋ฌธ์ ๋ฅผ ์ผ์ผํฌ ์์๋ ์์ด๋์ด๊ฐ ์์ต๋๊น?
2.4.0-beta4
์๋ํด ์ฃผ์๊ฒ ์ต๋๊น?
@hyochan ๊ฐ์ฌํฉ๋๋ค ๐
๋ด ํธ์์ ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋์์ต๋๋ค.
@IsaevTimur ์ด๋ป๊ฒ ํด๊ฒฐ ํ์ต๋๊น? ์ฌ์ ํ ์๋ํ์ง ์์ต๋๋ค.
@hyochan ์ฌ๊ธฐ ๋ด ์ธ์ฑ ๊ตฌ๋งค ๋ชจ๋์ ์ ์ฒด ์ฝ๋์ ๋๋ค.
import React, { Component } from 'react';
import { View, ImageBackground, TouchableOpacity, Image, Alert,
ActivityIndicator, Platform } from 'react-native';
import {inapp, btnBuy, purple} from '../helper/constants';
import ImageResizeMode from 'react-native/Libraries/Image/ImageResizeMode'
import { connect } from 'react-redux';
import { Icon } from 'native-base';
import { Actions } from 'react-native-router-flux';
import * as RNIap from 'react-native-iap';
import { getItems, getPurchase, fetchCategory } from '../action';
const itemSkus = Platform.select({
ios: [
'max_asl_unlimited_access'
],
android: [
'max_asl_unlimited_access'
]
});
class Banner extends Component {
constructor(props){
super(props);
this.onBuyNowPress = this.onBuyNowPress.bind(this);
this.forAndroid = this.forAndroid.bind(this);
this.forIOS = this.forIOS.bind(this);
}
state = {
loading: false,
}
async componentDidMount() {
try {
const result = await RNIap.initConnection();
console.log('result', result);
this.props.getItems();
} catch (err) {
console.warn(err.code, err.message);
}
}
componentDidUpdate(prevProps) {
if(prevProps.purchase !== this.props.purchase) {
this.props.fetchCategory();
}
}
onBuyNowPress() {
this.setState({ loading: true });
RNIap.getProducts(itemSkus).then(success => {
if(Platform.OS == "ios") {
this.forIOS()
} else {
this.forAndroid()
}
}).catch(error => {
alert(error);
this.setState({ loading: false });
})
}
async forIOS() {
console.log('BannerCall');
try {
const purchase = await RNIap.buyProduct('max_asl_unlimited_access');
console.log("BannerPurchase >>",purchase);
if(purchase) {
this.props.getPurchase();
this.setState({
loading: false,
});
console.log('Purchase succesfully')
}
} catch (err) {
console.log("BannerError >> ", err);
}
}
forAndroid() {
RNIap.buyProduct('max_asl_unlimited_access').then(purchase => {
this.props.getPurchase();
this.setState({
loading: false,
receipt: purchase.transactionReceipt,
});
console.log('Purchase succesfully')
Alert.alert("Purchase succesfully")
}).catch(err => {
console.log(err.code, err.message);
this.setState({ loading: false });
if(err.message === "You already own this item.") {
this.props.getPurchase();
Alert.alert("You already own this product, we are restoring your purchase.")
}
})
}
componentWillUnmount() {
RNIap.endConnection();
}
renderSpinner() {
if(this.state.loading) {
return (
<ActivityIndicator size="large" color="#F7CD52" />
)
}
return null
}
render() {
const { container, bannerStyle, btnContainer, iconClose } = styles;
return (
<View style={container}>
<ImageBackground source={inapp} style={bannerStyle} resizeMode={ImageResizeMode.contain}>
<Icon name="close" style={iconClose} type="FontAwesome" onPress={() => {Actions.pop()}}/>
<View style={btnContainer}>
{this.renderSpinner()}
<TouchableOpacity onPress={() => this.onBuyNowPress()}>
<Image source={btnBuy} />
</TouchableOpacity>
</View>
</ImageBackground>
</View>
);
}
}
const styles = {
container: {
flex: 1,
},
iconClose: {
color: '#FFF',
fontSize: 30,
alignSelf: 'flex-end',
margin: 20,
fontWeight: 'bold',
},
bannerStyle: {
flex: 1,
width: '100%',
height: '100%',
backgroundColor: purple
},
btnBuy: {
marginRight: 20,
marginTop: 160,
height: 85,
width: 215,
},
btnContainer: {
flex: 1,
marginTop: 50,
justifyContent: 'center',
alignItems: 'center'
}
};
function mapStateToProps({ purchase }) {
return { purchase };
}
export default connect(mapStateToProps, { getItems, getPurchase, fetchCategory })(Banner);
๋ฟก ๋นต๋จ
2.4.0-beta4๋ฅผ ์ฌ์ฉํ๊ณ ์๋์ง ํ์ธํ์ญ์์ค.
๋ํ SANDBOX ์ฌ์ฉ์ (๊ฐ๋ฐ ์ค)๋ฅผ ์ฌ์ฉํ๊ณ ์๋์ง ํ์ธํ์ญ์์ค. iTunes ์ฐ๊ฒฐ์์ ๊ตฌ์ฑ ํ ์ ์์ต๋๋ค. - ์ด๋ฌํ ์ฌ์ฉ์๋ ์ฌ๊ธฐ์ ์์ฑ https://appstoreconnect.apple.com/access/users ์๋ ๋ฐ์ค ์น์ ์์.
๋์์ด๋๊ธฐ๋ฅผ ๋ฐ๋๋๋ค :)
์๋
ํ์ธ์.
ํ์ง๋ง ๋ด ์ฑ ์คํ ์ด ๊ตฌ๋งค ํ๋ก์ธ์ค๊ฐ ์ ์๋ํ์ฌ ๋ชจ๋ ๊ฒ์ด ๊ตฌ์ฑ๋์ด ์์์ ์๋ฏธํ๋ฉฐ ์ 2.4.0-beta4๋ฅผ ์ฌ์ฉํฉ๋๋ค.
์ฌ๊ธฐ package.json ํ์ผ์ ๋ํ ํญ๋ชฉ์ ๋๋ค.
"react-native-iap": "^2.4.0-beta4",
๋ง์นจ๋ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐ @hyochan .. ์ I ์ํ I์ด ๊ด๊ณ ๋ฌผํ didntํ๋ ๊ฒฝ์ฐ ๋ฌธ์ ๋ await RNIap.finishTransaction();
๊ทธ ๋๋ () ๋ฉ์๋์์๋ค. ๋์ค์ ์ถ๊ฐํ์ต๋๋ค. ๊ทธ๊ฒ ๋ฌธ์ ์์ต๋๋ค. ํด๊ฒฐ์ฑ
์ ํธ๋์ญ์
( await RNIap.clearTransaction();
)์ ์ ๋ฆฌํด์ผํ๋๋ฐ ์๋ํฉ๋๋ค.
์ด ํ๋ฅญํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ํ ์ง์์ ๋ค์ ํ ๋ฒ ๊ฐ์ฌ๋๋ฆฝ๋๋ค.
@ ZeroCool00 ์ฑ๊ณต ์ถํํฉ๋๋ค !! ๋ค, ๊ทธ๋ฐ ์ข ๋ฅ์ ๋ฌธ์ ๋ ๋น์ ์ด ์๋ชปํ ๊ฒ์ ๋ํ ๊ฒฌ์ธ๋ ฅ์ด ํ์ํ๊ธฐ ๋๋ฌธ์ ๋น์ ํธ์์ ๋ ์ ํด๊ฒฐ๋์ด์ผํฉ๋๋ค. ๊ฐ์ ์ผ๋ก ๊ณ ํต๋ฐ์ ์์๋ ๋ถ๋ค์ ์ํด ๋ค์ ์ค์ ์ ๊ฐ์ฌํฉ๋๋ค.
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
2.4.0-beta4
์๋ํด ์ฃผ์๊ฒ ์ต๋๊น?