初步实现iap
This commit is contained in:
parent
d41253352e
commit
f28703244d
|
@ -11,6 +11,8 @@ npm-debug.*
|
||||||
web-build/
|
web-build/
|
||||||
test.jsx
|
test.jsx
|
||||||
example.jsx
|
example.jsx
|
||||||
|
ios
|
||||||
|
android
|
||||||
|
|
||||||
|
|
||||||
# macOS
|
# macOS
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
import React, { useState, createContext, useContext, useEffect } from "react";
|
||||||
|
import { Platform } from "react-native";
|
||||||
|
import Purchases, { LOG_LEVEL } from "react-native-purchases";
|
||||||
|
import { AuthContext } from "../App";
|
||||||
|
import { get } from "../utils/storeInfo";
|
||||||
|
|
||||||
|
const IapContext = createContext();
|
||||||
|
|
||||||
|
export const IapProvider = ({ children }) => {
|
||||||
|
const [isReady, setIsReady] = useState(false);
|
||||||
|
const [packages, setPackages] = useState([]);
|
||||||
|
|
||||||
|
const { state } = useContext(AuthContext);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const init = async () => {
|
||||||
|
if (Platform.OS === "ios" && state.isSignin) {
|
||||||
|
const account = await get("account");
|
||||||
|
await Purchases.configure({
|
||||||
|
apiKey: process.env.EXPO_PUBLIC_RC_APPLE_KEY,
|
||||||
|
appUserID: account.mid.toString(),
|
||||||
|
});
|
||||||
|
Purchases.setLogLevel(LOG_LEVEL.DEBUG);
|
||||||
|
await loadOfferings();
|
||||||
|
}
|
||||||
|
setIsReady(true);
|
||||||
|
};
|
||||||
|
init();
|
||||||
|
}, [state]);
|
||||||
|
|
||||||
|
const loadOfferings = async () => {
|
||||||
|
const offerings = await Purchases.getOfferings();
|
||||||
|
if (offerings.current) {
|
||||||
|
setPackages(offerings.current.availablePackages);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const purchasePackage = async (pack) => {
|
||||||
|
if (Platform.OS !== "ios") return;
|
||||||
|
try {
|
||||||
|
await Purchases.purchasePackage(pack);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCustomerInformation = async () => {
|
||||||
|
if (Platform.OS !== "ios") return;
|
||||||
|
try {
|
||||||
|
const customerInfo = await Purchases.getCustomerInfo();
|
||||||
|
return customerInfo;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const value = {
|
||||||
|
packages,
|
||||||
|
purchasePackage,
|
||||||
|
getCustomerInformation,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!isReady) return <></>;
|
||||||
|
|
||||||
|
return <IapContext.Provider value={value}>{children}</IapContext.Provider>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useIap = () => useContext(IapContext);
|
|
@ -40,6 +40,7 @@
|
||||||
"expo-clipboard": "~5.0.1",
|
"expo-clipboard": "~5.0.1",
|
||||||
"expo-constants": "~15.4.5",
|
"expo-constants": "~15.4.5",
|
||||||
"expo-crypto": "~12.8.1",
|
"expo-crypto": "~12.8.1",
|
||||||
|
"expo-dev-client": "~3.3.11",
|
||||||
"expo-device": "~5.9.3",
|
"expo-device": "~5.9.3",
|
||||||
"expo-file-system": "~16.0.8",
|
"expo-file-system": "~16.0.8",
|
||||||
"expo-image": "~1.10.6",
|
"expo-image": "~1.10.6",
|
||||||
|
@ -66,6 +67,7 @@
|
||||||
"react-native-pager-view": "6.2.3",
|
"react-native-pager-view": "6.2.3",
|
||||||
"react-native-parsed-text": "^0.0.22",
|
"react-native-parsed-text": "^0.0.22",
|
||||||
"react-native-picker-select": "^8.1.0",
|
"react-native-picker-select": "^8.1.0",
|
||||||
|
"react-native-purchases": "^7.27.2",
|
||||||
"react-native-reanimated": "~3.6.2",
|
"react-native-reanimated": "~3.6.2",
|
||||||
"react-native-safe-area-context": "4.8.2",
|
"react-native-safe-area-context": "4.8.2",
|
||||||
"react-native-screens": "~3.29.0",
|
"react-native-screens": "~3.29.0",
|
||||||
|
|
|
@ -8,6 +8,7 @@ import * as Clipboard from "expo-clipboard";
|
||||||
import Toast from "react-native-toast-message";
|
import Toast from "react-native-toast-message";
|
||||||
import MyModal from "../../components/MyModal";
|
import MyModal from "../../components/MyModal";
|
||||||
import baseRequest from "../../utils/baseRequest";
|
import baseRequest from "../../utils/baseRequest";
|
||||||
|
import { useIap } from "../../context/IapProvider";
|
||||||
|
|
||||||
export default function WebWithHeader({ navigation, route }) {
|
export default function WebWithHeader({ navigation, route }) {
|
||||||
//设置页面标题
|
//设置页面标题
|
||||||
|
@ -87,6 +88,13 @@ export default function WebWithHeader({ navigation, route }) {
|
||||||
Linking.openURL(data);
|
Linking.openURL(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//iap
|
||||||
|
const { packages, purchasePackage } = useIap();
|
||||||
|
const purchase = async (product) => {
|
||||||
|
const pack = packages.find((p) => p.identifier === product);
|
||||||
|
await purchasePackage(pack);
|
||||||
|
};
|
||||||
|
|
||||||
//唤起支付宝或微信
|
//唤起支付宝或微信
|
||||||
const handleUrlRedirect = (event) => {
|
const handleUrlRedirect = (event) => {
|
||||||
const { url } = event;
|
const { url } = event;
|
||||||
|
@ -154,14 +162,24 @@ export default function WebWithHeader({ navigation, route }) {
|
||||||
userAgent="FromWebview"
|
userAgent="FromWebview"
|
||||||
onMessage={async (event) => {
|
onMessage={async (event) => {
|
||||||
const msg = JSON.parse(event.nativeEvent.data);
|
const msg = JSON.parse(event.nativeEvent.data);
|
||||||
if (msg.type === "SAVE_IMAGE") {
|
switch (msg.type) {
|
||||||
saveImage(msg.data);
|
case "SAVE_IMAGE":
|
||||||
} else if (msg.type === "COPY_URL") {
|
saveImage(msg.data);
|
||||||
copy(msg.data);
|
break;
|
||||||
} else if (msg.type === "NAVIGATE") {
|
case "COPY_URL":
|
||||||
navigation.navigate(msg.data.page, { ...msg.data.params });
|
copy(msg.data);
|
||||||
} else if (msg.type === "OPEN_BROWSER") {
|
break;
|
||||||
openBrowser(msg.data);
|
case "NAVIGATE":
|
||||||
|
navigation.navigate(msg.data.page, { ...msg.data.params });
|
||||||
|
break;
|
||||||
|
case "OPEN_BROWSER":
|
||||||
|
openBrowser(msg.data);
|
||||||
|
break;
|
||||||
|
case "IAP":
|
||||||
|
purchase(msg.data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
injectedJavaScript={setCookieScript}
|
injectedJavaScript={setCookieScript}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import * as Clipboard from "expo-clipboard";
|
||||||
import Toast from "react-native-toast-message";
|
import Toast from "react-native-toast-message";
|
||||||
import MyModal from "../../components/MyModal";
|
import MyModal from "../../components/MyModal";
|
||||||
import baseRequest from "../../utils/baseRequest";
|
import baseRequest from "../../utils/baseRequest";
|
||||||
|
import { useIap } from "../../context/IapProvider";
|
||||||
|
|
||||||
export default function WebWithoutHeader({ navigation, route }) {
|
export default function WebWithoutHeader({ navigation, route }) {
|
||||||
//前往打开权限弹窗
|
//前往打开权限弹窗
|
||||||
|
@ -80,6 +81,13 @@ export default function WebWithoutHeader({ navigation, route }) {
|
||||||
Linking.openURL(data);
|
Linking.openURL(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//iap
|
||||||
|
const { packages, purchasePackage } = useIap();
|
||||||
|
const purchase = async (product) => {
|
||||||
|
const pack = packages.find((p) => p.identifier === product);
|
||||||
|
await purchasePackage(pack);
|
||||||
|
};
|
||||||
|
|
||||||
//唤起支付宝或微信
|
//唤起支付宝或微信
|
||||||
const handleUrlRedirect = (event) => {
|
const handleUrlRedirect = (event) => {
|
||||||
const { url } = event;
|
const { url } = event;
|
||||||
|
@ -147,14 +155,24 @@ export default function WebWithoutHeader({ navigation, route }) {
|
||||||
userAgent="FromWebview"
|
userAgent="FromWebview"
|
||||||
onMessage={async (event) => {
|
onMessage={async (event) => {
|
||||||
const msg = JSON.parse(event.nativeEvent.data);
|
const msg = JSON.parse(event.nativeEvent.data);
|
||||||
if (msg.type === "SAVE_IMAGE") {
|
switch (msg.type) {
|
||||||
saveImage(msg.data);
|
case "SAVE_IMAGE":
|
||||||
} else if (msg.type === "COPY_URL") {
|
saveImage(msg.data);
|
||||||
copy(msg.data);
|
break;
|
||||||
} else if (msg.type === "NAVIGATE") {
|
case "COPY_URL":
|
||||||
navigation.navigate(msg.data.page, { ...msg.data.params });
|
copy(msg.data);
|
||||||
} else if (msg.type === "OPEN_BROWSER") {
|
break;
|
||||||
openBrowser(msg.data);
|
case "NAVIGATE":
|
||||||
|
navigation.navigate(msg.data.page, { ...msg.data.params });
|
||||||
|
break;
|
||||||
|
case "OPEN_BROWSER":
|
||||||
|
openBrowser(msg.data);
|
||||||
|
break;
|
||||||
|
case "IAP":
|
||||||
|
purchase(msg.data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
injectedJavaScript={setCookieScript}
|
injectedJavaScript={setCookieScript}
|
||||||
|
|
57
yarn.lock
57
yarn.lock
|
@ -2318,6 +2318,11 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
nanoid "^3.1.23"
|
nanoid "^3.1.23"
|
||||||
|
|
||||||
|
"@revenuecat/purchases-typescript-internal@10.6.2":
|
||||||
|
version "10.6.2"
|
||||||
|
resolved "https://registry.npmmirror.com/@revenuecat/purchases-typescript-internal/-/purchases-typescript-internal-10.6.2.tgz#718c9f6e74e5673f53a1b612f930713783c2eafe"
|
||||||
|
integrity sha512-bWSNwhCyiiB0CGq5092PsADBeFFtAIr4jshKghY37dtPa1jpqck0ga77+BWT9jN/J4Jtq1ME/dKKg0hIuGI+LQ==
|
||||||
|
|
||||||
"@rneui/base@^4.0.0-rc.8":
|
"@rneui/base@^4.0.0-rc.8":
|
||||||
version "4.0.0-rc.8"
|
version "4.0.0-rc.8"
|
||||||
resolved "https://registry.npmmirror.com/@rneui/base/-/base-4.0.0-rc.8.tgz#6fbf9b3049a9207d47c3c53b70c0f68f3627a170"
|
resolved "https://registry.npmmirror.com/@rneui/base/-/base-4.0.0-rc.8.tgz#6fbf9b3049a9207d47c3c53b70c0f68f3627a170"
|
||||||
|
@ -2755,6 +2760,16 @@ aggregate-error@^3.0.0:
|
||||||
clean-stack "^2.0.0"
|
clean-stack "^2.0.0"
|
||||||
indent-string "^4.0.0"
|
indent-string "^4.0.0"
|
||||||
|
|
||||||
|
ajv@8.11.0:
|
||||||
|
version "8.11.0"
|
||||||
|
resolved "https://registry.npmmirror.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f"
|
||||||
|
integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==
|
||||||
|
dependencies:
|
||||||
|
fast-deep-equal "^3.1.1"
|
||||||
|
json-schema-traverse "^1.0.0"
|
||||||
|
require-from-string "^2.0.2"
|
||||||
|
uri-js "^4.2.2"
|
||||||
|
|
||||||
ajv@^8.11.0:
|
ajv@^8.11.0:
|
||||||
version "8.12.0"
|
version "8.12.0"
|
||||||
resolved "https://registry.npmmirror.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1"
|
resolved "https://registry.npmmirror.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1"
|
||||||
|
@ -4065,6 +4080,41 @@ expo-crypto@~12.8.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
base64-js "^1.3.0"
|
base64-js "^1.3.0"
|
||||||
|
|
||||||
|
expo-dev-client@~3.3.11:
|
||||||
|
version "3.3.11"
|
||||||
|
resolved "https://registry.npmmirror.com/expo-dev-client/-/expo-dev-client-3.3.11.tgz#f2541ccbcfc2ba32bcea47293bc9beae4e10db60"
|
||||||
|
integrity sha512-9nhhbfbskfmjp/tlRS5KvDpCoW0BREJBxpu2GyjKu7nDB33W8fJLL0wXgNhP+QEb93r37o3uezKmUm2kibOvTw==
|
||||||
|
dependencies:
|
||||||
|
expo-dev-launcher "3.6.9"
|
||||||
|
expo-dev-menu "4.5.8"
|
||||||
|
expo-dev-menu-interface "1.7.2"
|
||||||
|
expo-manifests "~0.13.0"
|
||||||
|
expo-updates-interface "~0.15.1"
|
||||||
|
|
||||||
|
expo-dev-launcher@3.6.9:
|
||||||
|
version "3.6.9"
|
||||||
|
resolved "https://registry.npmmirror.com/expo-dev-launcher/-/expo-dev-launcher-3.6.9.tgz#5e104e0533a46f3614c1691673da3351092e8d1d"
|
||||||
|
integrity sha512-MBDMAqjCMVYt1Zv47u2dJTp4d8gCZMfM4GWAFhfQy3G6XzkUlFtewaQefAqy93FcYOv6BYdC9yZOLOb06tqTfA==
|
||||||
|
dependencies:
|
||||||
|
ajv "8.11.0"
|
||||||
|
expo-dev-menu "4.5.8"
|
||||||
|
expo-manifests "~0.13.0"
|
||||||
|
resolve-from "^5.0.0"
|
||||||
|
semver "^7.5.3"
|
||||||
|
|
||||||
|
expo-dev-menu-interface@1.7.2:
|
||||||
|
version "1.7.2"
|
||||||
|
resolved "https://registry.npmmirror.com/expo-dev-menu-interface/-/expo-dev-menu-interface-1.7.2.tgz#772fb97c6b0a44c27965cdfcfa078f316b0930ca"
|
||||||
|
integrity sha512-V/geSB9rW0IPTR+d7E5CcvkV0uVUCE7SMHZqE/J0/dH06Wo8AahB16fimXeh5/hTL2Qztq8CQ41xpFUBoA9TEw==
|
||||||
|
|
||||||
|
expo-dev-menu@4.5.8:
|
||||||
|
version "4.5.8"
|
||||||
|
resolved "https://registry.npmmirror.com/expo-dev-menu/-/expo-dev-menu-4.5.8.tgz#21940385124c7d2745066bbcb42185ebd35f66bc"
|
||||||
|
integrity sha512-GXfI0CmYlqjOqyFjtplXO9PSoJQoy89+50lbUSNZykDsGyvzCPzl4txdQcdHHSglKYr7lWV7aeMVeehuSct60w==
|
||||||
|
dependencies:
|
||||||
|
expo-dev-menu-interface "1.7.2"
|
||||||
|
semver "^7.5.3"
|
||||||
|
|
||||||
expo-device@~5.9.3:
|
expo-device@~5.9.3:
|
||||||
version "5.9.3"
|
version "5.9.3"
|
||||||
resolved "https://registry.npmmirror.com/expo-device/-/expo-device-5.9.3.tgz#0ad61da681424aa682fa03001d0344394c01f8a1"
|
resolved "https://registry.npmmirror.com/expo-device/-/expo-device-5.9.3.tgz#0ad61da681424aa682fa03001d0344394c01f8a1"
|
||||||
|
@ -6587,6 +6637,13 @@ react-native-picker-select@^8.1.0:
|
||||||
"@react-native-picker/picker" "^1.8.3"
|
"@react-native-picker/picker" "^1.8.3"
|
||||||
lodash.isequal "^4.5.0"
|
lodash.isequal "^4.5.0"
|
||||||
|
|
||||||
|
react-native-purchases@^7.27.2:
|
||||||
|
version "7.27.2"
|
||||||
|
resolved "https://registry.npmmirror.com/react-native-purchases/-/react-native-purchases-7.27.2.tgz#435eecb86db412e66c81a9cd0887a726a17b8135"
|
||||||
|
integrity sha512-sLO85vTehwS4rlBJRmBYersIuNjmcjRJKvd5YY6y5xBVkw80LRJDmp7NTEfN9Dzp36XxnGb8KYcKOz1ZkubCXg==
|
||||||
|
dependencies:
|
||||||
|
"@revenuecat/purchases-typescript-internal" "10.6.2"
|
||||||
|
|
||||||
react-native-ratings@^8.1.0:
|
react-native-ratings@^8.1.0:
|
||||||
version "8.1.0"
|
version "8.1.0"
|
||||||
resolved "https://registry.npmmirror.com/react-native-ratings/-/react-native-ratings-8.1.0.tgz#3fa9ad29128dc3a88e59518ba151e61c59dd0647"
|
resolved "https://registry.npmmirror.com/react-native-ratings/-/react-native-ratings-8.1.0.tgz#3fa9ad29128dc3a88e59518ba151e61c59dd0647"
|
||||||
|
|
Loading…
Reference in New Issue