我正在尝试在我的Android React原生应用程序上实现Android计费4.0.0。
我曾尝试在我的build.gradle(app)中实现下面这行代码:
implementation 'com.android.billingclient:billing:4.0.0'
然而,当我包括上面的行时,我的React Native In App Purchase(RNIAP)已经停止工作。
在我的JS代码中,我有下面这行代码(如果需要,您可以查看下面的完整文件):
const products = await RNIap.getProducts(itemSkus);
然而,当我添加这一行时,RNIap.getProductsawait从来不返回任何东西,这一行后面的代码也不会执行,这一行似乎卡住了。
当我删除上面的行时,RNIap.getProducts会正常工作并显示应用内购买。但是,如果我删除上面的行,Google Play控制台会显示“请升级到计费库版本4或更高版本以发布此应用”,因此我无法上传新应用。
我知道这不是一个模拟器的问题,因为我已经发布了应用程序与上述行和在现场环境中的IAP仍然没有返回。
我已将以下内容包含在我的AndroidManifest.xml中
<uses-permission android:name="com.android.vending.BILLING" />
iOS上一切正常。
下面是我的代码:
(Note:出于安全原因,我更改了软件包名称和应用内购买名称)
iap.js
import React, { Component } from "react";
import {
View,
Text,
StyleSheet,
Platform,
PixelRatio,
} from "react-native";
import {Header,Left,Right,Icon,Content,Grid,Row,Col,Container,H1,Button,Footer} from 'native-base';
import LinearGradient from 'react-native-linear-gradient';
//Redux imports
import { connect } from "react-redux";
import { toggle } from '../../Reducers/toggle';
//In-app Purchase import
import * as RNIap from 'react-native-iap';
const itemSkus = Platform.select({
ios: [
'example.for_stackoverflow.ios',
],
android: [
'example.for_stackoverflow.android',
],
});
class Iap extends Component {
constructor(props) {
console.log(itemSkus);
super(props);
this.state = {
productList: [],
receipt: '',
availableItemsMessage: '',
};
}
state = {
toggle: this.props.toggle.togglePremium || false,
};
handleChange = ( toggle ) => {
this.setState({ toggle });
};
async componentDidMount() {
try {
const result = await RNIap.initConnection();
console.log('result', result);
} catch (err) {
console.warn(err.code, err.message);
}
this.getItems();
}
//after purcahse to to the finish transaction page.
goToNext = () => {
this.props.navigation.navigate('Logout', {
receipt: this.state.receipt,
});
}
getItems = async() => {
try {
console.log(itemSkus + ' check itemSkus');
const products = await RNIap.getProducts(itemSkus);
//const subscriptions = await RNIap.getSubscriptions(itemSkus);
// const products = await RNIap.getSubscriptions(itemSkus);
console.log(products + 'check Products');
this.setState({ productList: products });
} catch (err) {
console.log(err.message + ' err.message');
console.warn(err.code, err.message);
}
}
buyItem = async(sku) => {
//console.info('buyItem: ' + sku);
// const purchase = await RNIap.buyProduct(sku);
// const products = await RNIap.buySubscription(sku);
// const purchase = await RNIap.buyProductWithoutFinishTransaction(sku);
try {
const purchase: any = await RNIap.buyProduct(sku);
this.setState({ receipt: purchase.transactionReceipt }, () => this.goToNext());
} catch (err) {
//console.warn(err.code, err.message);
const subscription = RNIap.addAdditionalSuccessPurchaseListenerIOS(async (purchase) => {
this.setState({ receipt: purchase.transactionReceipt }, () => this.goToNext());
subscription.remove();
});
}
}
getPurchases = async() => {
try {
console.log('get hit, and when??');
const purchases = await RNIap.getAvailablePurchases();
let restoredTitles = '';
let coins = CoinStore.getCount();
purchases.forEach(purchase => {
if (purchase.productId == '4dot6OVER01') {
this.setState({ togglePremium: true });
restoredTitles += 'Premium Version';
}
else if (purchase.productId == 'android.test.purchased') {
console.log(purchase.productId);
this.setState({ togglePremium: true });
restoredTitles += 'Premium Version';
}
})
Alert.alert('Restore Successful', 'You successfully restored the following purchases: ' + restoredTitles);
} catch(err) {
//console.warn(err); // standardized err.code and err.message available
Alert.alert(err.message);
}
}
static navigationOptions = {
drawerIcon : ({tintColor}) => (
<Icon name="ios-star-outline" style={{fontSize: 24, color: tintColor}} />
)
}
getPrice = (priceString) => {
const price = JSON.parse(priceString);
//return (<H1 style={styles.textHeaderNumber}>${price}</H1>)
return(<Text style={styles.buttonTextBackWhite}>${price}</Text>)
}
getTitle = (titleString) => {
const title = JSON.parse(titleString);
return(<Row><H1 style={styles.textHeader}>{title}</H1></Row>)
}
getDescription = (descString) => {
const desc = JSON.parse(descString);
return(<Row><Text style={styles.textDesc}>{desc}</Text></Row>)
}
render() {
const purchase = this.props.toggle.togglePremium;
const { productList, receipt, availableItemsMessage } = this.state;
console.log(productList + ' check productList');
const receipt100 = receipt.substring(0, 100);
return (
<Col size={1}>
<Row><Text style={styles.textHeader}>Cricket Over Counter Premium</Text></Row>
<Row><Text style={styles.textDesc}>Cricket Umpire Over and Ball Counter upgrade to premium to allow all features for the entire innings!</Text></Row>
{
productList.map((product, i) => {
console.log(product + ' check product.');
return (
<Row key={i} style={{
flexDirection: 'column', alignItems: 'center',
}}>
<Button rounded large warning style={styles.largeButtonGreen}
onPress={() => this.buyItem(product.productId)} >
{this.getPrice(JSON.stringify(product.price))}
</Button>
</Row>
);
})
}
</Col>
);
}
}
const mapStateToProps = state => ({
toggle: state.toggle,
});
export default connect(mapStateToProps)(Iap);
package.json
{
"name": "ExampleForStackOverflow",
"version": "0.0.1",
"private": true,
"scripts": {
"android": "react-native run-android",
"ios": "react-native run-ios",
"start": "react-native start",
"test": "jest",
"lint": "eslint ."
},
"dependencies": {
"@invertase/react-native-apple-authentication": "^2.1.2",
"@react-native-async-storage/async-storage": "^1.13.4",
"@react-native-firebase/app": "^10.8.0",
"@react-native-firebase/auth": "^10.8.0",
"@react-native-firebase/firestore": "^10.8.0",
"@react-native-google-signin/google-signin": "^7.0.0-alpha.3",
"@react-native-picker/picker": "^1.16.7",
"@react-navigation/drawer": "^5.12.3",
"@react-navigation/native": "^5.9.2",
"native-base": "^2.15.2",
"react": "16.13.1",
"react-compose": "^2.0.0",
"react-native": "0.63.5",
"react-native-animatable": "^1.3.3",
"react-native-apple-authentication": "^2.0.0",
"react-native-cli": "^2.0.1",
"react-native-dotenv": "^3.3.1",
"react-native-draggable-flatlist": "^3.0.7",
"react-native-elements": "^3.2.0",
"react-native-gesture-handler": "^1.10.1",
"react-native-haptic-feedback": "^1.11.0",
"react-native-iap": "^5.2.14",
"react-native-keep-awake": "^4.0.0",
"react-native-linear-gradient": "^2.5.6",
"react-native-reanimated": "^1.13.4",
"react-native-restart": "0.0.24",
"react-native-safe-area-context": "^3.1.9",
"react-native-safe-area-view": "^1.1.1",
"react-native-screens": "^2.17.1",
"react-native-scroll-into-view": "^2.0.2",
"react-native-splash-screen": "^3.2.0",
"react-native-swipe-list-view": "^3.2.9",
"react-native-swipeable-item": "^2.0.2",
"react-native-switch": "^2.0.0",
"react-native-vector-icons": "^8.0.0",
"react-native-webview": "^11.2.3",
"react-navigation": "^4.4.3",
"react-navigation-drawer": "^2.6.0",
"react-redux": "^7.2.2",
"redux": "^4.0.5",
"redux-devtools-extension": "^2.13.8",
"redux-logger": "^3.0.6",
"redux-persist": "^6.0.0",
"redux-thunk": "^2.3.0",
"tcomb-form-native": "^0.6.20"
},
"devDependencies": {
"@babel/core": "^7.8.4",
"@babel/runtime": "^7.8.4",
"@react-native-community/eslint-config": "^1.1.0",
"babel-jest": "^25.1.0",
"eslint": "^6.5.1",
"jest": "^25.1.0",
"metro-react-native-babel-preset": "^0.59.0",
"react-test-renderer": "16.13.1"
},
"jest": {
"preset": "react-native"
}
}
希望有人经历过类似的问题,可以帮助我解决。
谢谢安德鲁
1条答案
按热度按时间zzoitvuj1#
我发现了问题所在。
我在“React本地0.63.5。我安装了React本地iap 5.2.14-它不支持Android计费库4.0.0。
因为我的React Native版本低于0.65,我必须更新我的React NativeIAP包到v7.5.6(因为这是最新的版本,支持React Native〈0.65和安卓计费库4.0.0)。
因此,对于任何可能遇到这个问题的人:
RN〈0.65 -升级到react-native-iap 7.5.6。通过更新package.json文件上的react-native-iap版本并运行npm install来执行此操作
RN〉= 0.65 -尝试通过更新package.json文件中的react-native-IAP版本并运行npm install来更新到react-native-IAP的最新稳定版本