react-native-iap I have problem with successfully make a subscription payment - react-native

Have anyone successfully implemented in app subscriptions with react-native-iap in an app.
I have tried to implement it but still very unstable. Can't rely that the subscription payments work every time. Sometimes the pay dialog won't show, sometimes it won't continue, and so on. Its a problem on both android and iOS.
Short explanation on how I have implemented it:
When clicked on pay button after the user has selected the plan, for ex. monthly.
await requestSubscription({
sku: subscription.productId,
...(offerToken && { subscriptionOffers: [{sku: subscription.productId, offerToken}]}),
})
Then I have to listeners, currentPurchaseError and currentPurchase that is returned as a hook from the rniap library.
React.useEffect(() => {
const onError = async () => {
// Do something on error from rniap.
}
if (currentPurchaseError) {
onError()
}
}, [currentPurchaseError])
And
React.useEffect(() => {
const checkCurrentPurchase = async () => {
// Do something, this should trigger when a purchase is successful.
}
if (currentPurchase) {
checkCurrentPurchase()
}
}, [currentPurchase, finishTransaction])
My receipt validation is happening on our own backend and its worth mentioning that everything there is working.
As I asked, has anyone implemented this successfully. If so, how?
Or is it worth thinking of changing to like revenue cat?
rniap's documentation and example code is really small and right now I need some help.
/Alexander
I have tried to get a successful payment within iOS sandbox but with no luck.

Related

Abort an Updates.fetchUpdateAsync() after a certain time [Expo/React native]

Expo React Native SDK Version: 46
Platforms: Android/iOS
Package concerned : Expo.Updates
Hello everyone, I want to programmatically check for new updates, without using the fallbackToCacheTimeout in app.json that will trigger the check of the new updates when the application is launched because like that I can't put a custom loading page.
So by doing this all by code as follow :
try{
const update = await Updates.checkForUpdateAsync();
if(update.isAvailable){
await Updates.fetchUpdateAsync();
await Updates.reloadAsync();
}else{}
}catch(err){}
But I want to be able to abort all those calls after a certain time (thus, the user that have a bad connection can use the app without waiting a very long time).
I check the documentation and I cannot found any method that allow this.
I dont't think it's possible to cancel a Promise for now in Javascript, or maybe any connection ?
Or does the "fallbackToCacheTimeout" value in the app.json will automatically apply to the fetch updates call of the Expo API?
Do someone have any idea how to do it ? :(
First of all I am assuming you have set updates.checkautomatically field to ON_ERROR_RECOVERY in app.json or app.config.js file. If not, please check the documentation. The reason why you need this is to avoid automatic updates which can also block your app on splash screen.
Updated Solution
Because of the limitation in javascript we can't cancel any external Promise (not created by us or when its reject method is not exposed to us). Also the function fetchUpdateAsync exposed to us is not a promise but rather contains fetch promise and returns its result.
So, here we have two options:
Cancel reloading the app to update after a timeout.
But note that updates will be fetched in background and stored on
the device. Next time whenever user restarts the app, update will
be installed. I think this is just fine as this approach doesn't
block anything for user and also there is a default timeout for http
request clients like fetch and axios so, request will error out in
case of poor/no internet connection.
Here is the code:
try {
const update = await Updates.checkForUpdateAsync();
if (update.isAvailable) {
const updateFetchPromise = Updates.fetchUpdateAsync();
const timeoutInMillis = 10000; // 10 seconds
const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject("timedout"), timeoutInMillis))
// This will return only one Promise
Promise.race([updateFetchPromise, timeoutPromise])
.then(() => Updates.reloadAsync())
.catch((error) => {
if (error === 'timedout') {
// Here you can show some toast as well
console.log("Updates were not cancelled but reload is stopped.")
} else if (error === 'someKnownError') {
// Handle error
} else {
// Log error and/or show a toast message
}
})
} else {
// Perform some action when update is not available
}
} catch (err) {
// Handle error
}
Change the expo-updates package just for your app using a patch
Here you can return a cancel method with Updates.fetchUpdateAsync() and use it with setTimeout to cancel the fetch request. I won't be providing any code for this part but if you are curious I can definitely provide some help.
Please refer this section to understand use of fallbackToCacheTimeout in eas updates.
Old solution:
Now, for aborting or bypassing the promise i.e. Updates.fetchUpdateAsync in your case. You can basically throw an Error in setTimeout after whatever time duration you want, so that, catch block will be executed, bypassing the promises.
Here is the old code :
try{
const update = await Updates.checkForUpdateAsync();
if(update.isAvailable){
// Throw error after 10 seconds.
const timeout = setTimeout(() => { throw Error("Unable to fetch updates. Skipping..") }, 10000)
await Updates.fetchUpdateAsync();
// Just cancel the above timeout so, no error is thrown.
clearTimeout(timeout)
await Updates.reloadAsync();
}else{}
}catch(err){}

Remove listener AppState change react native

Good evening everyone, I am facing a problem.
I am developing an app in react-native and I need that, every time a user sends the app in the background or in an inactive state, when he returns to the app I force him to go to a certain screen (Loading) where I perform certain checks (such as if he is a blocked user, deleted, etc ...).
I have now written the following function
const [appState, setAppState] = useState(AppState.currentState);
useEffect(() => {
getAttivita();
getBanner();
const appStateListener = AppState.addEventListener(
"change",
(nextAppState) => {
setAppState(nextAppState);
if (nextAppState === "active") {
navigation.dispatch(
CommonActions.reset({
index: 0,
routes: [{ name: Routes.Loading }],
})
);
}
}
);
return () => {
appStateListener?.remove();
};
}, []);
I put this listener in the Screen Diary (which represents my home).
Now if from the screen Diary, I minimize the app, then I have no problems and everything works as it should.
However if I go to another screen and minimize the app, then I get the following error
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
in Diary (at SceneView.tsx:122)
Then when I log back into the app I realize that the listener for the app status is still active (so it is as if the remove () had not worked) and in fact I am pushed back into my loading screen.
So I'm wondering, is it the listener that isn't actually being removed?
Or am I doing something wrong?
Thanks in advance to who will answer me .

react-native how to remove persistence on firebase snapshot

I am little confused.
I am listening to firebase snapshot with sample code below
unsubscribe = firebase
.firestore()
.collection('collection')
.doc(id)
.onSnapshot(
function(doc) {
// other code
},
);
This will listen to the collection if there's new item for the specific id.
Then, closing the app will unsubscribe to the snapshot
useEffect(() => {
return () => {
if (unsubscribe) {
unsubscribe()
}
}
}, []);
It is working fine.
However, given the scenario.
If the snapshot triggered (eg. { value: 1 }) and then I closed the app.
Removed the value on the firebase for the specific id. (meaning the id should not received the item)
Re-open the app
I still get the previous value which is { value: 1} and then get the newest value which is undefined (since i removed the value)
Is the value persists on the app? How can I remove this one upon re-opening of the app?
Thanks!
From this answer:
There is now a feature in the API for clearing persistence. It is not recommended for anything but tests, but you can use
firebase.firestore().clearPersistence().catch(error => {
console.error('Could not enable persistence:', error.code);
})
It must run before the Firestore database is used.

pouchdb live is a little too fast for realtime chat

I am using the current vuex mutation to sync to my pouch/ couchdb which is excellent. However
As I am typing into text box I can type too fast and this can mean letters are not sent to sync, which is annoying but not a killer however if I edit in the middle and type at speed sometimes cursor will jump to the end, I want live as its live text but I would like to poll a little slower does anyone have any suggests.... there was a suggestion of using since : 'now' but that doesnt seem to slow it down
syncDB: () => {
pouchdb.replicate.from(remote).on('complete', function () {
store.commit('GET_ALL_NODES')
store.commit('GET_MY_NODES')
store.commit('GET_POSITIONS')
store.commit('GET_CONNECTIONS')
store.commit('GET_EMOJI')
// turn on two-way, continuous, retriable sync
pouchdb
.sync(remote, {
live: true,
retry: true,
attachments: true,
})
.on('change', function () {
// pop info into function to find out more
store.commit('GET_ALL_NODES')
store.commit('GET_MY_NODES')
store.commit('GET_POSITIONS')
store.commit('GET_CONNECTIONS')
store.commit('GET_EMOJI')
})
.on('paused', function () {
// replication paused (e.g. replication up to date, user went offline)
// console.log('replication paused')
})
.on('active', function () {
// replicate resumed (e.g. new changes replicating, user went back online)
//console.log('back active')
})
.on('denied', function () {
// a document failed to replicate (e.g. due to permissions)
})
.on('complete', function () {
// handle complete
})
.on('error', function (err) {
console.log(err)
})
})
},
I added a debounce via lodash to the text input which helps a lot it’s not perfect especially if you are editing in the middle of text but less jumps to the end and general start speedier typing isn’t an issue

AsyncStorage.removeItem(key) not removing items unless App restarted or after several minutes

I have a logout Button that binds to the following method.
async onLogoutButtonPress() {
await AsyncStorage.removeItem('accessToken');
await AsyncStorage.removeItem('mobileNumber');
await AsyncStorage.removeItem("businessId");
await AsyncStorage.clear();
this.props.navigation.navigate('Login');
}
I understand that AsyncStorage.removeItem is an asynchronous operation and it returns a Promise. However notice that I am using await that waits for Promise to resolve before navigating to Login.
I also tried the alternate then syntax
AsyncStorage.removeItem(('accessToken')).then(() => {console.log('resolved') },
() => { console.log('rejected') })
And all of them show as resolved in the console, but some how the items persist unless I close and restart the app. I am seeing this behavior on Android.
Why aren't the items getting removed until I restart the app ?
I am using expo for the build, if that matters.
I am using
import { AsyncStorage} from 'react-native';
Here's the react-native version.
"react-native": "https://github.com/expo/react-native/archive/sdk-34.0.0.tar.gz",