I’ve a react native app that’s utilizing expo. I’m attempting to implement IAP purchases for IOS. as customers signal as much as the app. Is it potential to have IAP added to my app while my app is configured this fashion with expo? I’ve the app setup in my apple developer account as properly so I do know this is not the problem.
I can not get the IAP purchases working throughout the app and particularly with the kinds from Typescript
I’ve been getting this error which makes me assume this isn’t potential.
ERROR Error: E_IAP_NOT_AVAILABLE
This error is positioned at:
in WrapperComponent (created by withDevTools(WrapperComponent))
in withDevTools(WrapperComponent)
in RCTView (created by View)
in View (created by AppContainer)
in RCTView (created by View)
in View (created by AppContainer)
in AppContainer
in essential(RootComponent), js engine: hermes
That is the present setup that I’ve for for attempting to implement IAP.
.That is the signup web page:
import React, { useEffect, useState } from "react";
import {
View,
TextInput,
Picture,
Textual content,
StyleSheet,
KeyboardAvoidingView,
ActivityIndicator,
Platform,
TouchableOpacity,
} from "react-native";
import { FIREBASE_AUTH } from "../../api/firebase";
import { createUserWithEmailAndPassword } from "firebase/auth";
import PrimaryButton from "../../elements/PrimaryButton/PrimaryButton";
import CustomProgressBar from "../../elements/ProgressBar/ProgressBar";
import SecondaryButton from "../../elements/SecondaryButton/SecondaryButton";
import { RouterProps } from "../../App";
import { useValidEmail, useValidPassword } from "../../hooks/useAuthHooks";
import { createUser } from "../../api/person";
import { UserProfile } from "../../fashions/UserProfile";
import { CheckBox } from "react-native-elements";
import {
PurchaseError,
RequestSubscription,
requestSubscription,
useIAP,
validateReceiptIos,
} from "react-native-iap";
export kind NewUser = {
uid?: string;
firstName?: string;
lastName?: string;
e mail: string;
};
const PLATFORM = Platform.OS;
const subscriptionSkus = Platform.choose({
ios: ["****"],
});
const SignupScreen = ({ navigation }: RouterProps) => {
const [loading, setLoading] = useState(false);
const [screen, setScreen] = useState<"signupOne" | "signupTwo">("signupOne");
const { e mail, setEmail, emailIsValid } = useValidEmail("");
const { password, setPassword, passwordIsValid } = useValidPassword("");
const [isChecked, setChecked] = useState<boolean>(false);
const {
password: passwordConfirm,
setPassword: setPasswordConfirm,
passwordIsValid: passwordConfirmIsValid,
} = useValidPassword("");
const [newUser, setNewUser] = useState<NewUser>({ e mail: e mail });
const createUserInAuth = async (newUser: NewUser, password: string) => {
attempt {
const response = await createUserWithEmailAndPassword(
FIREBASE_AUTH,
newUser.e mail,
password
);
return response;
} catch (error) {
console.log(error);
}
};
const handleValidation = async () => {
setLoading(true);
if (!newUser.e mail) {
setLoading(false);
return alert("Please enter an Electronic mail");
}
if (!emailIsValid) {
setLoading(false);
return alert("Please enter a legitimate Electronic mail");
}
if (!password) {
setLoading(false);
return alert("Please enter a Password");
}
if (!passwordIsValid) {
setLoading(false);
return alert("Please enter a legitimate Password");
}
if (!passwordConfirm) {
setLoading(false);
return alert("Please verify your Password");
}
if (!passwordConfirmIsValid) {
setLoading(false);
return alert("Please verify your legitimate Password");
}
if (password !== passwordConfirm) {
setLoading(false);
return alert("Passwords do not match");
}
if (!newUser.firstName) {
setLoading(false);
return alert("Please enter an First Identify");
}
if (!newUser.lastName) {
setLoading(false);
return alert("Please enter an Final Identify");
}
setScreen("signupTwo");
setLoading(false);
return true;
};
const {
linked,
subscriptions,
getSubscriptions,
currentPurchase,
finishTransaction,
purchaseHistory,
getPurchaseHistory,
} = useIAP();
const handleBuySubscription = async (subscriptionId: any) => {
attempt {
setLoading(true);
const buy = await requestSubscription(subscriptionId as RequestSubscription);
console.log("Buy profitable:", buy);
navigation!.navigate("Signin");
setLoading(false);
} catch (error: any) {
console.warn("Error buying:", error.message);
setLoading(false);
// Deal with buy failure
}
};
const handleSignUp = async () => {
setLoading(true);
if (!isChecked && display === "signupTwo") {
setLoading(false);
return alert("Please settle for the Phrases and Situations and Privateness Coverage");
}
attempt {
const response = await createUserInAuth(newUser, password);
if (newUser.firstName && newUser.lastName && response && subscriptionSkus) {
const createdUser: UserProfile = {
uid: response?.person.uid,
firstName: newUser!.firstName,
lastName: newUser!.lastName,
e mail: e mail,
};
if(PLATFORM === "ios") {
await handleBuySubscription(subscriptionSkus[0])
} else if(PLATFORM === "android"){
return
}
await createUser(createdUser)
.then(() => {
setLoading(false);
navigation!.navigate("SignIn");
console.log("Person added to database");
})
.catch((error) => {
console.log("Error signing up:", error);
alert("Join failed: " + error.message);
setLoading(false);
});
}
} catch (error) {
console.error("Error including person: ", error);
}
}
const screens = {
signupOne: (
<>
<TextInput
model={types.enter}
placeholder="First identify"
onChangeText={(worth) =>
setNewUser((previous) => ({ ...previous, firstName: worth }))
}
worth={newUser?.firstName}
autoCapitalize="phrases"
/>
<TextInput
model={types.enter}
placeholder="Final identify"
onChangeText={(worth) =>
setNewUser((previous) => ({ ...previous, lastName: worth }))
}
worth={newUser?.lastName}
autoCapitalize="phrases"
/>
<TextInput
model={types.enter}
placeholder="Electronic mail"
onChangeText={(worth) => {
setEmail(worth);
setNewUser((previous) => ({ ...previous, e mail: worth }));
}}
worth={e mail}
autoCapitalize="none"
/>
<TextInput
model={types.enter}
placeholder="Password"
onChangeText={setPassword}
worth={password}
secureTextEntry
autoCapitalize="none"
/>
<TextInput
model={types.enter}
placeholder="Verify Password"
onChangeText={setPasswordConfirm}
worth={passwordConfirm}
secureTextEntry
autoCapitalize="none"
/>
</>
),
signupTwo: (
<>
<Textual content model={types.value}>Annual value of $60</Textual content>
<View model={[styles.flexed, { width: 300 }]}>
<CheckBox
checked={isChecked}
onPress={() => (isChecked ? setChecked(false) : setChecked(true))}
containerStyle={types.checkbox}
/>
<Textual content
model={types.hereText}
onPress={() => navigation!.navigate("TermsAndConditions")}
>
I settle for the Phrases and Situations and Privateness Coverage
</Textual content>
</View>
</>
),
};
return (
<View model={types.container}>
<KeyboardAvoidingView habits="padding" model={types.contentContainer}>
<CustomProgressBar
progress={loading ? 1 : display === "signupOne" ? 0.33 : 0.66}
/>
<Picture
supply={require("../../property/connection.png")}
model={types.emblem}
/>
{screens[screen]}
{loading ? (
<ActivityIndicator measurement="massive" colour="#0000ff" />
) : (
<PrimaryButton
title={display === "signupOne" ? "Subsequent" : "Create"}
onPress={() => {
display === "signupOne" ? handleValidation() : handleSignUp();
}}
/>
)}
<SecondaryButton
title="Again"
onPress={() => {
display === "signupOne"
? navigation!.navigate("SignIn")
: setScreen("signupOne");
}}
/>
</KeyboardAvoidingView>
</View>
);
};
const types = StyleSheet.create({
value: {
borderColor: "#7FB3D5",
borderRadius: 10,
paddingVertical: 15,
paddingHorizontal: 40,
marginTop: 10,
colour: "black",
borderWidth: 1,
backgroundColor: "clear",
},
checkbox: {
alignSelf: "heart",
},
emblem: {
width: 100,
top: 100,
marginBottom: 20,
marginTop: 20,
},
field: {
margin: 10,
marginBottom: 5,
padding: 10,
backgroundColor: "white",
borderRadius: 7,
shadowColor: "rgba(0, 0, 0, 0.45)",
shadowOffset: { top: 16, width: 0 },
shadowOpacity: 0.1,
shadowRadius: 12,
},
button: {
alignItems: "heart",
backgroundColor: "mediumseagreen",
borderRadius: 8,
padding: 10,
},
buttonText: {
fontSize: 16,
fontWeight: "daring",
colour: "white",
textTransform: "uppercase",
},
specialTag: {
colour: "white",
backgroundColor: "crimson",
width: 125,
padding: 4,
fontWeight: "daring",
fontSize: 12,
borderRadius: 7,
marginBottom: 2,
},
flexed: {
flexDirection: "row",
alignItems: "heart",
},
hereText: {
marginLeft: 5,
textDecorationLine: "underline",
colour: "blue",
},
signupContainer: {
marginTop: 80,
alignItems: "heart",
},
container: {
flex: 1,
justifyContent: "heart",
alignItems: "heart",
backgroundColor: "#D9D9D9",
},
contentContainer: {
flex: 1,
justifyContent: "heart",
alignItems: "heart",
width: 300,
},
title: {
fontSize: 24,
marginBottom: 20,
},
enter: {
width: 300,
top: 40,
backgroundColor: "white",
borderColor: "black",
borderWidth: 1,
padding: 5,
marginBottom: 10,
},
errorText: {
colour: "pink",
fontSize: 14,
marginBottom: 10,
},
});
export default SignupScreen;
That is the App.tsx:
import React, { useState, useEffect } from "react";
import {
NavigationContainer,
NavigationProp,
RouteProp,
} from "@react-navigation/native";
import { createStackNavigator } from "@react-navigation/stack";
import { FIREBASE_AUTH } from "./api/firebase";
import { onAuthStateChanged, Person } from "firebase/auth";
import SettingsPage from "./pages/SettingsPage";
import { AppRegistry } from "react-native";
import Calculator from "./pages/Calculator";
import ChangePassword from "./pages/ChangePassword";
import { QueryClient, QueryClientProvider } from "react-query";
import UpdateUser from "./pages/UpdateUser";
import HelpPage from "./pages/HelpPage";
import ForgotPassword from "./pages/ForgotPassword"
import PresetValues from "./pages/PresetValues";
// import { InAppUtils } from 'react-native-iap';
import TermsAndConditions from "./pages/auth/TermsAndConditions";
import HomeScreen from "./pages/HomeScreen";
import WorkerPage from "./pages/WorkerPage";
import BayCalculator from "./pages/BayCalculator";
import TeamPage from "./pages/TeamPage";
import LoginScreen from "./pages/auth/Login";
import SignupScreen from "./pages/auth/Signup";
import LoadingScreen from "./pages/Loading";
import { withIAPContext } from "react-native-iap";
AppRegistry.registerComponent("bay-calculator", () => App);
// InAppUtils.ios.consumePurchase('your-subscription-product-id');
const queryClient = new QueryClient();
export interface RouterProps {
navigation?: NavigationProp<any, any>;
route?: RouteProp<any, any>;
}
const Stack = createStackNavigator();
const InsideStack = createStackNavigator();
const AuthStack = createStackNavigator();
operate App() {
const [isLoading, setIsLoading] = useState(true);
const [user, setUser] = useState<Person | null>(null);
operate InsideLayout({ navigation }: { navigation: any }) {
return (
<InsideStack.Navigator>
<InsideStack.Display
identify="House"
element={HomeScreen}
choices={{ headerShown: false }}
/>
<InsideStack.Display
identify="WorkerPage"
element={WorkerPage}
choices={{ headerShown: false }}
/>
<InsideStack.Display
identify="SettingsPage"
element={SettingsPage}
choices={{ headerShown: false }}
/>
<InsideStack.Display
identify="BayCalculator"
element={BayCalculator}
choices={{ headerShown: false }}
/>
<InsideStack.Display
identify="Calculator"
element={Calculator}
choices={{ headerShown: false }}
/>
<InsideStack.Display
identify="TeamPage"
element={TeamPage}
choices={{ headerShown: false }}
/>
<InsideStack.Display
identify="ChangePassword"
element={ChangePassword}
choices={{ headerShown: false }}
/>
<InsideStack.Display
identify="UpdateUser"
element={UpdateUser}
choices={{ headerShown: false }}
/>
<InsideStack.Display
identify="HelpPage"
element={HelpPage}
choices={{ headerShown: false }}
/>
<InsideStack.Display
identify="PresetValues"
element={PresetValues}
choices={{ headerShown: false }}
/>
</InsideStack.Navigator>
);
}
operate AuthLayout() {
return (
<AuthStack.Navigator>
<Stack.Display
identify="SignIn"
element={LoginScreen}
choices={{ headerShown: false }}
/>
<Stack.Display
identify="SignUp"
element={SignupScreen}
choices={{ headerShown: false }}
/>
<Stack.Display
identify="ForgotPassword"
element={ForgotPassword}
choices={{ headerShown: false }}
/>
<InsideStack.Display
identify="TermsAndConditions"
element={TermsAndConditions}
choices={{ headerShown: false }}
/>
</AuthStack.Navigator>
);
}
useEffect(() => {
attempt {
onAuthStateChanged(FIREBASE_AUTH, (person) => {
setUser(person);
setIsLoading(false);
});
} catch (err) {
console.log(err);
}
}, []);
return (
<QueryClientProvider consumer={queryClient}>
<NavigationContainer>
<Stack.Navigator initialRouteName="SignIn">
{isLoading ? (
<Stack.Display
identify="Loading"
element={LoadingScreen}
choices={{ headerShown: false }}
/>
) : person ? (
<Stack.Display
identify="Inside"
element={InsideLayout}
choices={{ headerShown: false }}
/>
) : (
<Stack.Display
identify="Auth"
element={AuthLayout}
choices={{ headerShown: false }}
/>
)}
</Stack.Navigator>
</NavigationContainer>
</QueryClientProvider>
);
}
export default withIAPContext(App)