I want to access the phone camera roll photos, in React-native by this code:
_handleButtonPress = () => {
CameraRoll.getPhotos({
first: 20,
assetType: 'Photos',
})
.then(r => {
this.setState({ photos: r.edges });
})
.catch((err) => {
alert(err)
});
};
but i get this Error in alert:
could not get photos need: read_external_storage permission
As mentioned in the Google Docs, if the device is running Android 6.0 (API level 23) or higher, and the app's targetSdkVersion is 23 or higher, the user isn't notified of any app permissions at install time.
Therefore you must ask the user to grant the dangerous permissions at runtime
Here's a list of Dangerous Permissions.
You can enable the permissions in React Native as
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,
{
'title': 'Access Storage',
'message': 'Access Storage for the pictures'
}
)
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
console.log("You can use read from the storage")
} else {
console.log("Storage permission denied")
}
} catch (err) {
console.warn(err)
}
Check here for more details
i added this code in AndroidManifest located at(( Example/android/app/src/main/AndroidManifest.xml)):
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
then i confirmed app permissions in android(and i dont know how to do it at run time) and problem solved.
Related
I am new to react native. I am trying to store signature in my mobile internal storage. or in app itself. but I do not know how to store this signature image in phone internal storage or in app storage. please help . here is code
base64:null,
_onSaveEvent = (result) => {
this.setState({base64: result.pathName})
console.log(this.state.base64)
<SignatureCapture
style={styles.signature}
ref="sign"
onSaveEvent={this._onSaveEvent}
onDragEvent={this._onDragEvent}
showNativeButtons={false}
showTitleLabel={false}
viewMode={'portrait'}
/>
}
result.pathName return this path =
/storage/emulated/0/saved_signature/signature.png
but there is know folder caller saved_signature. so what to do.
npm install --save rn-fetch-blob
For android only AndroidManifest.xml
<!-- Required -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<!-- Include this only if you are planning to use the camera roll -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Include this only if you are planning to use the microphone for video recording -->
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<!-- Required -->
<application android:requestLegacyExternalStorage="true" ... />
// check for permission
const checkAndroidPermission = async () => {
if (Platform.OS === 'ios') {
save();
} else {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
// Once user grant the permission start downloading
save();
} else {
if (Platform.OS === 'android') {
ToastAndroid.show('Storage Permission denied.', ToastAndroid.SHORT);
} else {
AlertIOS.alert('Storage Permission denied.');
}
}
} catch (err) {
// To handle permission related exception
console.warn('tryerr', err);
}
}
};
const save= async () => {
const paths = `${
RNFetchBlob.fs.dirs.DCIMDir
}/${new Date().getTime()}.jpg`; // where u need to put that
try {
RNFetchBlob.fs
.writeFile(paths, data.base64, 'base64')//data.base64 is your photo with convert base64
.then((value) => {
RNFetchBlob.fs
.scanFile([{path: paths}]) //after save to notify gallry for that
.then(() => {
console.log('scan file success');
})
.catch((err) => {
console.log('scan file error');
});
})
.catch((e) => console.log(e.message));
} catch (error) {
console.log('fileerror', error.message);
}
}
my this help you
use this to store your photo in internal storage rn-fatch-blob
if you don't understand this then told me i will share a code also to store a file in your photo with custom folder path
No Location Permission pop up in ios app nor can see Permissions options in the settings of the App
Works fine on Android. As I can use PermissionsAndroid to get the permissions.
Already used the following options in the info.plist by looking at the other answers. Few answers only mentioned about android.
info.plist
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Location Permission</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Location Permission</string>
<key>NSLocationUsageDescription</key>
<string>GPS data is required to...</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Location Permission</string>
codeinthefile.js
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
{
title: "Geolocation Permission",
message: "App needs access to your phone's location.",
}
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
Geolocation.getCurrentPosition(
position => {
Geocoder.from({
latitude: position.coords.latitude,
longitude: position.coords.longitude,
})
.then(json => {
console.log(json);
})
.catch(error => {
console.log(error);
});
},
error => {
console.log(error);
},
{ enableHighAccuracy: true, timeout: 15000, maximumAge: 10000 }
);
} else {
console.log('Location permission not granted!);
}
} catch (err) {
console.log('Location permission not granted!)
}
If by using the above-mentioned values in info.plist I should get the access to location then there should not be an error of no permission granted.
Don't use PermissionAndroid in iOS, is enough to put the permission requirement in the info.plist,
try something like,
if(Platform.OS === "ios"){
// your code using Geolocation and asking for authorisation with
geolocation.requestAuthorization()
}else{
// ask for PermissionAndroid as written in your code
}
Thank you, Doug and David, Based on your suggestion I have made then changes to my code in the following way which worked for me:
if(Platform.OS === 'ios'){
Geolocation.requestAuthorization();
this.getGeoLocation();
}else {
let granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
{
title: "App Geolocation Permission",
message: "App needs access to your phone's location.",
}
);
if (androidGranted === PermissionsAndroid.RESULTS.GRANTED) {
this.getGeoLocation();
} else {
console.log('Location permission not granted!!!!');
}
}
Use below for both android and ios permissions .
import {Platform} from 'react-native';
import {request, PERMISSIONS, RESULTS} from 'react-native-permissions';
....
export async function getLocationPermissions() {
const granted = await request(
Platform.select({
android: PERMISSIONS.ANDROID.ACCESS_COARSE_LOCATION,
ios: PERMISSIONS.IOS.LOCATION_WHEN_IN_USE,
}),
{
title: 'DemoApp',
message: 'DemoApp would like access to your location ',
},
);
return granted === RESULTS.GRANTED;
}
....
// usage
const granted = await getLocationPermissions();
I am trying to implement google sign in on my app and every thing running well , it ask me to choose account on press of sign in button but it response it send me code 16 "CANCELLED" error.
I've installed library by npm install react-native-google-sign-in.
Then I linked it. I created a new project on firebase and download google-services.json from there and paste it in android/app. Also generated release SHA1 and add in firebase project.
componentDidMount() {
GoogleSignin.configure({
//It is mandatory to call this method before attempting to call signIn()
scopes: ['https://www.googleapis.com/auth/drive.readonly'],
// Repleace with your webClientId generated from Firebase console
webClientId:
'my client id',
});
}
Google sign in button and action
<TouchableOpacity
onPress={() => _signIn()}
style={{height:50,width:50,borderRadius:50}}
>
<Image
style={{height:50,width:50}}
resizeMode='contain'
source={ImagePath.GOOGLE_ICON}
/>
</TouchableOpacity>
_signIn = async () => {
//Prompts a modal to let the user sign in into your application.
try {
await GoogleSignin.hasPlayServices({
//Check if device has Google Play Services installed.
//Always resolves to true on iOS.
showPlayServicesUpdateDialog: true,
});
const userInfo = await GoogleSignin.signIn();
alert(JSON.stringify(userInfo))
console.log('User Info --> ', userInfo);
this.setState({ userInfo: userInfo });
} catch (error) {
console.log('Message', error.message);
if (error.code === statusCodes.SIGN_IN_CANCELLED) {
console.log('User Cancelled the Login Flow');
} else if (error.code === statusCodes.IN_PROGRESS) {
console.log('Signing In');
} else if (error.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
console.log('Play Services Not Available or Outdated');
} else {
alert(JSON.stringify(error))
console.log('Some Other Error Happened',error);
}
}
};
These are my signing config
release {
if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) {
storeFile file(MYAPP_RELEASE_STORE_FILE)
storePassword MYAPP_RELEASE_STORE_PASSWORD
keyAlias MYAPP_RELEASE_KEY_ALIAS
keyPassword MYAPP_RELEASE_KEY_PASSWORD
}
}
I expect successful google sign in and user data in response. Any kind of help will be appreciated.Thank you
The fix to this is to add SHA1 to the firebase.
If you are testing for debug build then add debug SHA1 and for release build use release SHA1.
After adding SHA1 certificate fingerprints to the firebase.
Download and add the firebase google-services.json file to /android/app/
You can create a debug key by below command
cd android
gradlew signingReport
OR
cd android && ./gradlew signingReport
Reference link
Please share your AndroidManifest.xml file. Please check whether you have added any launch mode in manifest. If so please remove.
I am trying to get push notifications / firebase messaging to work with react native - I have gotten as far as checking / requesting permission, and I implemented onMessage, but I don't get any of my test messages (sent from the firebase developer console online, in the cloud messaging section). One thing that is odd is when I check the status of a completed message, it says no messages were sent (0 sent), so I don't even know if my app is getting the chance to receive a test message. Here is my code:
HomeScreen.js (the default route of the root navigator)
export default class HomeScreen extends React.Component {
....
componentDidMount() {
firebase.messaging()
.hasPermission()
.then(enabled => {
if (!enabled) {
this._getPermission();
}
firebase.messaging().getToken()
.then(fcmToken => {
if (fcmToken) {
// user has a device token
} else {
alert("User doesn't have a token yet");
}
}).catch((error) => {
alert(error);
});
firebase.messaging().subscribeToTopic('all').catch((error) => {alert(error)});
this.onTokenRefreshListener = firebase.messaging().onTokenRefresh(fcmToken => {
// Process your token as required
});
this.messageListener = firebase.messaging().onMessage((message: RemoteMessage) => {
// Process your message as required
alert(message);
});
}).catch((error) => {alert(error)});
}
_getPermission = () => {
firebase.messaging()
.requestPermission()
.catch(error => {
// User has rejected permissions
this._getPermission();
});
};
....
componentWillUnmount() {
this.onTokenRefreshListener();
this.messageListener();
firebase.messaging().unsubscribeFromTopic('all');
}
....
AppDelegate.h
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import UserNotifications;
#interface AppDelegate : UIResponder <UIApplicationDelegate, UNUserNotificationCenterDelegate>
#property (nonatomic, strong) UIWindow *window;
#end
AppDelegate.m
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "AppDelegate.h"
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import "RNFirebaseNotifications.h"
#import "RNFirebaseMessaging.h"
#import <Firebase.h>
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[FIRApp configure];
[RNFirebaseNotifications configure];
NSURL *jsCodeLocation;
for (NSString* family in [UIFont familyNames])
{
NSLog(#"%#", family);
for (NSString* name in [UIFont fontNamesForFamilyName: family])
{
NSLog(#" %#", name);
}
}
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:#"index" fallbackResource:nil];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:#"snagit"
initialProperties:nil
launchOptions:launchOptions];
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
[[UNUserNotificationCenter currentNotificationCenter] setDelegate:self];
return YES;
}
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
[[RNFirebaseNotifications instance] didReceiveLocalNotification:notification];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo
fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler{
[[RNFirebaseNotifications instance] didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
[[RNFirebaseMessaging instance] didRegisterUserNotificationSettings:notificationSettings];
}
#end
My BUNDLE_ID's all appear to be correct. Why aren't the messages being sent in the first place and/or, why am I not receiving them?
UPDATE
Would trying FCM help? https://github.com/evollu/react-native-fcm
UPDATE
My request was bad, I got a curl try to work with:
curl -i -H 'Content-type: application/json' -H 'Authorization:
key=server-key'
-XPOST https://fcm.googleapis.com/fcm/send -d '{"to": "/topics/all","data": {"message": "This is a Firebase Cloud Messaging
Topic Message!"}}'
I received:
HTTP/2 200
content-type: application/json; charset=UTF-8
date: Tue, 18 Sep 2018 21:38:21 GMT
expires: Tue, 18 Sep 2018 21:38:21 GMT
cache-control: private, max-age=0
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
server: GSE
alt-svc: quic=":443"; ma=2592000; v="44,43,39,35"
accept-ranges: none
vary: Accept-Encoding
{"message_id":5323681878653027379}
So why doesn't it work coming from the firebase web console? Could this be an issue that needs to be resolved by firebase?
UPDATE
To further test whether or not this is on the firebase side of things I wrote a cloud function that should send a notification when a certain document is updated/created/deleted:
exports.sendMessageNotification = functions.firestore().document('conversations/{conversationID}/messages/{messageID}').onWrite((change, context) => {
// Get an object representing the document
// e.g. {'name': 'Marie', 'age': 66}
const newValue = change.after.data();
// ...or the previous value before this update
const previousValue = change.before.data();
// access a particular field as you would any JS property
//const name = newValue.name;
var topic = 'all';
var payload = {
notification: {
title: "You got a new Message",
body: newValue.notification.body,
}
};
admin.messaging().sendToTopic(topic, payload)
.then(function(response) {
console.log("Successfully sent message:", response);
})
.catch(function(error) {
console.log("Error sending message:", error);
});
});
Here is my code which successfully writes an object to the above firestore location:
....
constructor() {
super();
this.onTokenRefreshListener = firebase.messaging().onTokenRefresh(fcmToken => {
// Process your token as required
});
this.messageListener = firebase.messaging().onMessage((message: RemoteMessage) => {
// Process your message as required
alert(message);
});
//this.ref = firebase.firestore().collection('items');
//this.authSubscription = null;
}
....
componentDidMount() {
firebase.messaging().getToken()
.then(fcmToken => {
if (fcmToken) {
console.log(fcmToken);
// Add a new document with a generated id.
const addMessage = firebase.firestore().collection('conversations').doc('1234567').collection('messages').doc('1234567');
data = {
notification: {
title: "You got a new Message",
body: "You got a new message",
}
}
// Set the 'capital' field of the city
const updateMessage = addMessage.update(data).catch((error) => {
alert(error);
addMessage.set(data).catch((error) => {
alert(error);
});
});
} else {
alert("User doesn't have a token yet");
}
}).catch((error) => {
alert(error);
});
....
}
For output I see the console.log(fcmToken) message. When I check the firebase functions log, I see Successfully sent message: { messageId: 6994722519047563000 }. When I check firestore, the document was created (or updated) correctly and it is in the correct place to be noticed (and it is on the firebase side according to the firebase function logs) - but I still never receive an actual notification on my iPhone.
Why am I not receiving the message if it is being sent?
UPDATE
I am now receiving notifications from the logic I created with firebase functions, the firebase web console just seems like it isn't working - the notifications still never get sent.
Solution
First of all, you need to get push notification in your device (not simulators).
I recommend to test with iOS and Android devices from firebase web console first. This process is not required codes on your delegate files handling push notifications except checking permission.
Anyway, suppose you do not have any android device and it is not working on your iOS device,
check bundle ids and GoogleService-Info.plist in firebase and XCode.
check your target capabilities on XCode. Push Notifications and Background Mode
Check app's permission of notification on iOS's setting
Why?
I am not sure how you set your firebase and XCode, but problems of push notifications from firebase web console are related in permissions, XCode setting and other settings normally.
In my case, typos of the bundle id in firebase settings was the problem.
If you can, you would test on Android also.
I develop a react-native (expo) mobile app and try to sign in with a google account to firebase, but I get an error:
"auth/operation-not-supported-in-this-enviroment. This operation is not supported in the enviroment this application is running on. "location.protocol" must be http, https or chrome-extension and web storage must be enabled"
Code:
loginGoogle() {
var provider = new firebase.auth.GoogleAuthProvider();
provider.addScope('profile');
provider.addScope('email');
firebase.auth().signInWithPopup(provider).then(function(result) {
var token = result.credential.accessToken;
var user = result.user;
return true;
}).catch(function(error) {
alert(error.code + '\n' +
error.message + '\n' +
error.email + '\n' +
error.credential);
return false;
});
}
signInWithPopup is not supported in react-native. You will need to use a third party OAuth library to get the OAuth ID token or access token and then sign in with Firebase:
const cred = firebase.auth.GoogleAuthProvider.credential(googleIdToken, googleAccessToken);
firebase.auth().signInWithCredential(cred)
.then((result) => {
// User signed in.
})
.catch((error) => {
// Error occurred.
});
Firebase does not support signInWithPopup in a React Native environment.
You can view a full list of supported environments on this page.
You can also submit a feature request for extended Firebase support for React Native here.
If you are using expo bare workflow or simple React native cli (or in simple words which contain android and ios folder) then simply use "React Native Firebase" library.
Here is the link https://rnfirebase.io/
But if you are using expo managed workflow(which donot contain android and ios folder ) then you have to follow below steps .
1.setup google developer account
use this guide to setup : https://docs.expo.dev/versions/latest/sdk/google/
Note that: use host.exp.exponent as the package name.
Another problem you may face in this step is generation of hash,which I also faced,the reason for that error is java dev kit(JDK) is not install ,so do install it before proceeding to this step.
2.Setup Firebase account
Simply setup firebase project as you set before, enable google sign in service
but this time the only change is you have to add client ID of your google developer account in (safest client id field) which will popup once you click on edit Google signin in firebase
look like this
3.Coding Part
import * as Google from 'expo-google-app-auth'; //imported from expo package
import {
GoogleAuthProvider,getAuth
} from 'firebase/auth';
import { initializeApp } from "firebase/app";
import { firebaseconfig } from '[your firebase credentials]';
const app=intitializeApp(firebaseconfig)
const auth=getAuth(app);
async function signInWithGoogleAsync() {
try {
const result = await Google.logInAsync({
androidClientId: 'cliend id from google dev console',
iosClientId: 'client id from google dev console for ios app(if you setup)',
scopes: ['profile', 'email'],
});
if (result.type === 'success') {
console.log(result)
const credential = GoogleAuthProvider.credential(result.idToken, result.accessToken);
// Sign in with credential from the Facebook user.
signInWithCredential(auth, credential)
.then(async result => {
console.log(result)
})
.catch(error => { console.log(error) });
return result.accessToken;
} else {
console.log("cancelled by user")
return { cancelled: true };
}
} catch (e) {
console.log(e);
return { error: true };
}//
}