Kiếm thêm thu nhập với mobile app như nào?

Kiếm thêm thu nhập với mobile app như nào? Đây là vấn đề dù đã được bàn luận rất lâu nhưng vẫn không thể hết hot được? Nào là phát triển các app theo xu hướng, nào là các app kết hợp với công nghệ đang phát triển (AI, AR,..), app bảo mật, On-demand apps,... những cách kiếm tiền từ app mobile dễ dàng hơn như In-app advertising hay là in-app-purchase,...

Tiêu đề hào nhoáng câu view vậy thôi chứ hôm nay mình sẽ chia sẻ về cách tích hợp in-app-purchase với react-native 😋

I . Chuẩn bị

Điều đầu tiên các bạn cần là đã có tài khoản developer trên google store và apple store và đã public app.

Cài đặt thư viện

yarn add react-native-iap

reac-native link react-native-iap

Trước khi run ios bạn cần chạy cd ios && pod install && cd ..

II. Config

1. iOS 🤗

Đầu tiên bạn cần vào ItunesConnect và hoàn thành mục Agreements, Tax and Bankings.

Tiếp theo ta cần enable In-app-purchase trên xcode nên (nếu như bạn không thấy nó đâu thì check lại xem tài khoản của bạn đã là tài khoản develop chưa nhá, hoặc đã enable nó trên configuage chưa)

Enable trên console develop

Tiếp theo bạn cần vào version mới nhất với state Ready to Submit ở tab Features và chọn In-App Purchases. Sau đó là điền các product bạn có như dưới hình đây

Các bạn lưu ý các tên item nhá, về sau mình sẽ demo và cần đó: non.consume.prod, point_1000, point_5000

1. Android 😔

Android thì lại đơn giản hơn bạn chỉ cần đăng nhập và app và thêm các product của bạn https://play.google.com/apps/publish

Tên các products: point_1000, 10000_point, 5000_point

Thêm quyền trong Manifest.xml

<uses-permission android:name="com.android.vending.BILLING" />

II. Setup code và test nào

Do mình chỉ có tài khoản dev trên android nên mình demo trên android nhá, ios bạn chỉ cần bật in-app-purchase trên xcode và thêm sản phẩm như ở trên mình nói là được thôi

Đầu tiên bạn tạo 1 view với 1 button, khi click vào sản phẩm đó thì truyền product id đó để lấy thông tin nó trên store. Ở đây mình truyền 1 product id là android.test.purchased, nó tương đương mấy cái point_1000, 10000_point, 5000_point ở trên mình bảo ấy, mình tạo khác đi thôi ☹️

...

requestPurchase = async (sku): void => {
    ...
}

...

<View style={styles.container}>
    <TouchableOpacity
          style={styles.btnBuy}
          onPress={(): void =>
            this.requestPurchase('android.test.purchased')
          }
        >
            <Text> BUY NOW</Text>
        </TouchableOpacity>
</View>

...

const styles = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
    },
    btnBuy: {
        flex: 0.5,
        backgroundColor: '#1CB5B4',
    },
    txtBtn: {
        color: 'white',
        fontSize: 14,
        fontWeight: "bold",
    },
})

...

Tiếp theo cần phải config một chút để kiểm tra xem ta connect với store như nào, thanh toán ra sao có lỗi không

async componentDidMount() {
    try {
      const result = await RNIap.initConnection();
      await RNIap.consumeAllItemsAndroid();
      console.log('result', result);
    } catch (err) {
      console.warn(err.code, err.message);
    }

    this.purchaseUpdateSubscription = purchaseUpdatedListener((purchase: InAppPurchase | SubscriptionPurchase | ProductPurchase ) => {
      console.log('purchaseUpdatedListener', purchase);
      const receipt = purchase.transactionReceipt;
      if (receipt) {
        yourAPI.deliverOrDownloadFancyInAppPurchase(purchase.transactionReceipt)
        .then((deliveryResult) => {
          if (isSuccess(deliveryResult)) {
            // Tell the store that you have delivered what has been paid for.
            // Failure to do this will result in the purchase being refunded on Android and
            // the purchase event will reappear on every relaunch of the app until you succeed
            // in doing the below. It will also be impossible for the user to purchase consumables
            // again untill you do this.
            if (Platform.OS === 'ios') {
              RNIap.finishTransactionIOS(purchase.transactionId);
            } else if (Platform.OS === 'android') {
              // If consumable (can be purchased again)
              RNIap.consumePurchaseAndroid(purchase.purchaseToken);
              // If not consumable
              RNIap.acknowledgePurchaseAndroid(purchase.purchaseToken);
            }

            // From [email protected] you can simplify above `method`. Try to wrap the statement with `try` and `catch` to also grab the `error` message.
            RNIap.finishTransaction(purchase);
          } else {
            // Retry / conclude the purchase is fraudulent, etc...
          }
        });
      }
    });
    
    this.purchaseErrorSubscription = purchaseErrorListener((error: PurchaseError) => {
      console.warn('purchaseErrorListener', error);
    });
}

componentWillUnmount(): void {
    if (this.purchaseUpdateSubscription) {
      this.purchaseUpdateSubscription.remove();
      this.purchaseUpdateSubscription = null;
    }
    if (this.purchaseErrorSubscription) {
      this.purchaseErrorSubscription.remove();
      this.purchaseErrorSubscription = null;
    }
 }

Các bạn nên vào docs đọc các Api để hiểu hơn nhá 😶

Cuối cùng là hàm xử lý của chúng ta

requestPurchase = async (sku): void => {
    try {
      const products = await RNIap.getProducts(
        Platform.select({
          ios: [
            sku
          ],
          android: [
            sku
          ],
        })
      );
      console.log('Products', products);
      this.setState({ productList: products });
    } catch (err) {
      console.warn(err.code, err.message);
    }

    try {
      RNIap.requestPurchase(sku, false);
    } catch (err) {
      Alert.alert(err.message);
    }
 };

Nếu các bạn làm đúng sẽ được như hình giống mình 😀

Welcome to React Native ☹️