Implementing app tracking transparency permission request on Expo 45 - react-native

I have a managed-expo (sdk 45) application and for some reason apple rejects my application because they are unable to locate the App Tracking Transparency permission request. I know it has something to do with expo-ads-admob. I am getting this message:
Please explain where we can find the App Tracking Transparency permission request in your app. The request should appear before any data is collected that could be used to track the user.
If you've implemented App Tracking Transparency but the permission request is not appearing on devices running the latest OS, please review the available documentation and confirm App Tracking Transparency has been correctly implemented.If your app does not track users, update your app privacy information in App Store Connect to undeclare tracking. You must have the Account Holder or Admin role to update app privacy information.
I'm using expo-ads-admob and this is how I did it (docs):
I installed expo-tracking-transparency
and added the function on the first part of the application (App.tsx)
import * as React from "react";
import { requestTrackingPermissionsAsync } from "expo-tracking-transparency";
export default function App() {
React.useEffect(() => {
(async () => {
const { status } = await requestTrackingPermissionsAsync();
if (status === "granted") {
console.log("Yay! I have user permission to track data");
}
})();
}, []);
return (
<MainApplication />
);
}
I also added
"plugins": [
[
"expo-tracking-transparency",
{
"userTrackingPermission": "This identifier will be used to deliver personalized ads to you."
}
]
]
To app.json
Then I use the component (everywhere in the app) like this:
<AdMobBanner
bannerSize={
Platform.OS === "ios" ? "fullBanner" : "smartBannerLandscape"
}
adUnitID={
Platform.OS == "ios"
? "IOS_ADMOB_CODE"
: "ANDROID_ADMOB_CODE"
}
servePersonalizedAds={false}
onDidFailToReceiveAdWithError={() => {}}
onAdViewDidReceiveAd={() => {}}
/>
It works, but iOS keep rejecting my application claiming they can't find the permission. I looked everywhere and saw this is the right way to implement this but unfortunately it didn't work.
Thanks in advance!

if you dont have infoplist go to and add the Description here.
enter image description here

Related

Expo-Auth session is not working properly

While implementing google login using the expo-auth-session package , I am getting some error that i don't have any idea about, It has been more than one day since i am stuck in this problem i cannot find a reliable source to use for implementing google login in my expo application. Is there any other way i can implement it in the react native expo application.
The error i am getting are :
WARN Linking requires a build-time setting `scheme` in the project's Expo config (app.config.js or app.json) for production apps, if it's left blank, your app may crash. The scheme does not apply to development in the Expo client but you should add it as soon as you start working with Linking to avoid creating a broken build. [Learn more][1]:
WARN EventEmitter.removeListener('url', ...): Method has been deprecated. Please instead use `remove()` on the subscription returned by `EventEmitter.addListener`.
WARN Possible Unhandled Promise Rejection (id: 2):
Error: Exception in HostFunction: Malformed calls from JS: field sizes are different.
What should i do ??
The link to the documentation that i followed is :-
And this is what i used from the documentation.
import * as Google from "expo-auth-session/providers/google";
import * as WebBrowser from "expo-web-browser";
WebBrowser.maybeCompleteAuthSession();
const [request, response, promptAsync] = Google.useAuthRequest({
expoClientId: expoClientId,
});
const login = ()=>{
useEffect(() => {
if (response?.type === "success") {
const { authentication } = response;
console.log(authentication);
}
}, [response]);
return (
<Pressable style={styles.btn} onPress={promptAsync}>
<Image
source={require("../../../assets/g1.png")}
style={styles.img}
/>
<Text style={styles.text}>Sign in with Google</Text>
</Pressable>
)
}
thank you any help would be appriciated.
In your app.json add following
"scheme":"com.yourpackage.yourapp"
this value must be same as your android.package and ios.bundleIdentifier

Expo - How to make custom permission message

I need to change the camera message when I try to reach user's camera.
It returns default "Allow xx to use your camera" message and I want to change It with my own permission message.
Where to change It and how?
Here's my camera code below.
useEffect(() => {
(async function () {
const { status } = await Camera.requestPermissionsAsync()
setHasPermission(status === 'granted')
})()
}, [])
From the Expo documentation:
To request permissions on iOS, you have to describe why the permissions are requested and install the library that can request this permission. In the managed workflow, you can do that by customizing the ios.infoPlist property in your app.json file. When using the bare workflow, you have to edit the info.plist file directly.
So, in app.json:
"infoPlist": {
"NSCameraUsageDescription": "This app uses the camera to scan barcodes on event tickets."
}
In a non-managed workflow, you can edit NSCameraUsageDescription in your Info.plist for the app in Xcode.

How to setup sendSignInLinkToEmail() from Firebase in react-native?

Working on a react-native project using #react-native-firebase/app v6 we recently integrated signing in with a "magic link" using auth.sendSignInLinkToEmail
We couldn't find a good example on how to setup everything in react-native and had different problems like
- auth/invalid-dynamic-link-domain - The provided dynamic link domain is not configured or authorized for the current project.
- auth/unauthorized-continue-uri - Domain not whitelisted by project
Searching for information and implementing the "magic link login" I've prepared a guide on how to have this setup in react-native
Firebase project configuration
Open the Firebase console
Prepare firebase instance (Email Link sign-in)
open the Auth section.
On the Sign in method tab, enable the Email/Password provider. Note that email/password sign-in must be enabled to use email link sign-in.
In the same section, enable Email link (passwordless sign-in) sign-in method.
On the Authorized domains tab (just bellow)
Add any domains that will be used
For example the domain for the url from ActionCodeSettings needs to be included here
Configuring Firebase Dynamic Links
For IOS - you need to have an ios app configured - Add an app or specify the following throughout the firebase console
Bundle ID
App Store ID
Apple Developer Team ID
For Android - you just need to have an Android app configured with a package name
Enable Firebase Dynamic Links - open the Dynamic Links section
“Firebase Auth uses Firebase Dynamic Links when sending a link that is meant to be opened in a mobile application.
In order to use this feature, Dynamic Links need to be configured in the Firebase Console.”
(ios only) You can verify that your Firebase project is properly configured to use Dynamic Links in your iOS app by opening
the following URL: https://your_dynamic_links_domain/apple-app-site-association
It should show something like:
{
"applinks": {
"apps": [],
"details": [
{
"appID": "AP_ID123.com.example.app",
"paths": [
"NOT /_/", "/"
]
}
]
}
}
IOS Xcode project configuration for universal links
Open the Xcode project and go to the Info tab create a new URL type to be used for Dynamic Links.
Enter a unique value in Identifier field and set the URL scheme field to be your bundle identifier, which is the default URL scheme used by Dynamic Links.
In the Capabilities tab, enable Associated Domains and add the following to the Associated Domains list: applinks:your_dynamic_links_domain
(!) This should be only the domain - no https:// prefix
Android
Android doesn’t need additional configuration for default or custom domains.
Packages
A working react-native project setup with react-native-firebase is required, this is thoroughly covered in the library own documentation, here are the specific packages we used
Note: using the dynamicLinks package can be replaced with react-native's own Linking module and the code would be almost identical
Exact packages used:
"#react-native-firebase/app": "^6.7.1",
"#react-native-firebase/auth": "^6.7.1",
"#react-native-firebase/dynamic-links": "^6.7.1",
Sending the link to the user email
The module provides a sendSignInLinkToEmail method which accepts an email and action code configuration.
Firebase sends an email with a magic link to the provided email. Following the link has different behavior depending on the action code configuration.
The example below demonstrates how you could setup such a flow within your own application:
EmailLinkSignIn.jsx
import React, { useState } from 'react';
import { Alert, AsyncStorage, Button, TextInput, View } from 'react-native';
import auth from '#react-native-firebase/auth';
const EmailLinkSignIn = () => {
const [email, setEmail] = useState('');
return (
<View>
<TextInput value={email} onChangeText={text => setEmail(text)} />
<Button title="Send login link" onPress={() => sendSignInLink(email)} />
</View>
);
};
const BUNDLE_ID = 'com.example.ios';
const sendSignInLink = async (email) => {
const actionCodeSettings = {
handleCodeInApp: true,
// URL must be whitelisted in the Firebase Console.
url: 'https://www.example.com/magic-link',
iOS: {
bundleId: BUNDLE_ID,
},
android: {
packageName: BUNDLE_ID,
installApp: true,
minimumVersion: '12',
},
};
// Save the email for latter usage
await AsyncStorage.setItem('emailForSignIn', email);
await auth().sendSignInLinkToEmail(email, actionCodeSettings);
Alert.alert(`Login link sent to ${email}`);
/* You can also show a prompt to open the user's mailbox using 'react-native-email-link'
* await openInbox({ title: `Login link sent to ${email}`, message: 'Open my mailbox' }); */
};
export default EmailLinkSignIn;
We're setting handleCodeInApp to true since we want the link from the email to open our app and be handled there. How to configure and handle this is described in the next section.
The url parameter in this case is a fallback in case the link is opened from a desktop or another device that does not
have the app installed - they will be redirected to the provided url and it is a required parameter. It's also required to
have that url's domain whitelisted from Firebase console - Authentication -> Sign in method
You can find more details on the supported options here: ActionCodeSettings
Handling the link inside the app
Native projects needs to be configured so that the app can be launched by an universal link as described
above
You can use the built in Linking API from react-native or the dynamicLinks #react-native-firebase/dynamic-links to intercept and handle the link inside your app
EmailLinkHandler.jsx
import React, { useState, useEffect } from 'react';
import { ActivityIndicator, AsyncStorage, StyleSheet, Text, View } from 'react-native';
import auth from '#react-native-firebase/auth';
import dynamicLinks from '#react-native-firebase/dynamic-links';
const EmailLinkHandler = () => {
const { loading, error } = useEmailLinkEffect();
// Show an overlay with a loading indicator while the email link is processed
if (loading || error) {
return (
<View style={styles.container}>
{Boolean(error) && <Text>{error.message}</Text>}
{loading && <ActivityIndicator />}
</View>
);
}
// Hide otherwise. Or show some content if you are using this as a separate screen
return null;
};
const useEmailLinkEffect = () => {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
const handleDynamicLink = async (link) => {
// Check and handle if the link is a email login link
if (auth().isSignInWithEmailLink(link.url)) {
setLoading(true);
try {
// use the email we saved earlier
const email = await AsyncStorage.getItem('emailForSignIn');
await auth().signInWithEmailLink(email, link.url);
/* You can now navigate to your initial authenticated screen
You can also parse the `link.url` and use the `continueurl` param to go to another screen
The `continueurl` would be the `url` passed to the action code settings */
}
catch (e) {
setError(e);
}
finally {
setLoading(false);
}
}
};
const unsubscribe = dynamicLinks().onLink(handleDynamicLink);
/* When the app is not running and is launched by a magic link the `onLink`
method won't fire, we can handle the app being launched by a magic link like this */
dynamicLinks().getInitialLink()
.then(link => link && handleDynamicLink(link));
// When the component is unmounted, remove the listener
return () => unsubscribe();
}, []);
return { error, loading };
};
const styles = StyleSheet.create({
container: {
...StyleSheet.absoluteFill,
backgroundColor: 'rgba(250,250,250,0.33)',
justifyContent: 'center',
alignItems: 'center',
},
});
const App = () => (
<View>
<EmailLinkHandler />
<AppScreens />
</View>
);
You can use the component in the root of your app as in this example
Or you can use it as a separate screen/route - in that case the user should be redirected to it after
the sendSignInLinkToEmail action
Upon successful sign-in, any onAuthStateChanged listeners will trigger with the new authentication state of the user. The result from the signInWithEmailLink can also be used to retrieve information about the user that signed in
Testing the email login link in the simulator
Have the app installed on the running simulator
Go through the flow that will send the magic link to the email
Go to your inbox and copy the link address
Open a terminal and paste the following code
xcrun simctl openurl booted {paste_the_link_here}
This will start the app if it’s not running
It will trigger the onLink hook (if you have a listener for it like above)
References
Deep Linking In React Native Using Firebase Dynamic Links
React Native Firebase - Dynamic Links
React Native Firebase - auth - signInWithEmailLink
firebase.google.com - Passing State In Email Actions
firebase.google.com - Authenticate with Firebase Using Email Link in JavaScript

How to detect screenshots with React Native (both Android and iOS)

I am trying to detect if a user takes a screenshot while using a smartphone app that I have built. I am building my project with React Native.
I have been told that I can possibly prevent screenshots for Android but not for iOS. but can I still detect whether a user attempts to take a screenshot so that I can at least send a warning via Alert?
Thanks in advance
I tried react-native-screenshot-detector but it did not work
you can use this package it supports android&ios screenshot detecting react-native-detector
import {
addScreenshotListener,
removeScreenshotListener,
} from 'react-native-detector';
// ...
React.useEffect(() => {
const userDidScreenshot = () => {
console.log('User took screenshot');
};
const listener = addScreenshotListener(userDidScreenshot);
return () => {
removeScreenshotListener(listener);
};
}, []);
There is no package for it currently.

How to force users to update the app using react native

I have updated my app on app and play store and I want to force my app users to update the new version of app in App store and playstore.
You can check for the App Store / Play Store version of your app by using this library
react-native-appstore-version-checker.
In expo app you can get the current bundle version using Constants.nativeAppVersion. docs.
Now in your root react native component, you can add an event listener to detect app state change. Every time the app transitions from background to foreground, you can run your logic to determine the current version and the latest version and prompt the user to update the app.
import { AppState } from 'react-native';
class Root extends Component {
componentDidMount() {
AppState.addEventListener('change', this._handleAppStateChange);
}
_handleAppStateChange = (nextState) => {
if (nextState === 'active') {
/**
Add code to check for the remote app version.
Compare it with the local version. If they differ, i.e.,
(remote version) !== (local version), then you can show a screen,
with some UI asking for the user to update. (You can probably show
a button, which on press takes the user directly to the store)
*/
}
}
componentWillUnmount() {
AppState.removeEventListener('change', this._handleAppStateChange);
}
}
import VersionCheck from 'react-native-version-check';
i have used version check lib for this purpose and approach i used is below. if version is lower i'm opening a modal on which an update button appears, and that button redirects to app store/google play
componentDidMount() {
this.checkAppUpdate();
}
checkAppUpdate() {
VersionCheck.needUpdate().then(res => {
if (res.isNeeded) {
setTimeout(() => {
this.setState({openModal: true});
});
}
});
}
updateApp = () => {
VersionCheck.getStoreUrl({
appID: 'com.showassist.showassist',
appName,
})
.then(url => {
Linking.canOpenURL(url)
.then(supported => {
if (!supported) {
} else {
return Linking.openURL(url);
}
})
.catch(err => console.error('An error occurred', err));
})
.catch(err => {
console.log(`error is: ${err}`);
});
};
For future readers.
If you are using Expo managed workflow, install this package react-native-version-check-expo using yarn add react-native-version-check-expo or npm install react-native-version-check-expo.
Consult the package documentation on Github for usage guidelines.
I'm using react-native-version-check-expo library to achieve this. Working fine for me.
if you are looking for an easy to integrate built in solution. You can use App Upgrade https://appupgrade.dev/ service to force update your mobile apps.
Create new version entry for your app version that you want to update in the app upgrade service and select whether you want to force it or just want to let users know that new version is available.
Integrate your app with App Upgrade using available SDK. Official SDK are available for React Native, Flutter, Expo, Android and iOS(Swift).
The SDK will take care of the rest.
Whenever you want to force upgrade a version just create a version entry in app upgrade dashboard.
You can also integrate using API. Just call the appupgrade api from your app with the required details such as your app version, platform, environment and app name.
The API will return you the details.. that this app needs to be updated or not.
Based on the response you can show popup in your app.You can call this API when app starts or periodically to check for the update. You can even provide a custom message.
API response:
See the response has force update true. So handle in the app by showing popup.
You can find the complete user documentation here. https://appupgrade.dev/docs
Thanks.