Our app allows the user take pictures (and select pictures) from it.
I've used the Expo component ImagePicker for that, as it provides a simple API.
And it works perfectly inside expo (both exp start and exp publish), but it does not work within a standalone apk.
When I try to invoke ImagePicker.launchCameraAsync(), I catch an EUNSPECIFIED exception, but that only in the standalone apk.
Details
An excerpt of the code:
import { ImagePicker } from 'expo';
(...)
const image = await ImagePicker.launchCameraAsync({
allowsEditing: true,
aspect: [3, 5],
});
(...)
let image = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
aspect: [3, 5],
});
It works well within expo, including exp publish version.
As for my permissions in the app.json, what I have is the following:
(...)
"android": {
"package": "br.com.miredefamilia",
"versionCode": 3,
"permissions": [
"android.permissions.CAMERA",
"android.permissions.READ_INTERNAL_STORAGE",
"android.permissions.READ_EXTERNAL_STORAGE"
]
}
I have also tried without the android.permissions.
The mobile does request for the permission, I accept it, and it does not launch the camera / picker, like it does within the expo.
Any help?
This is the proper solution with docs link
Ask for Permission.CAMERA and Permission.CAMERA_ROLL
const { status } = await Permissions.askAsync(Permissions.CAMERA, Permissions.CAMERA_ROLL)
if (status === 'granted') {
ImagePicker.launchCameraAsync({
mediaTypes: 'Images',
allowsEditing: true,
aspect: [1, 1]
})
} else {
// ask user to turn on permission here
}
Also update the app.json with this permissions
CAMERA
READ_EXTERNAL_STORAGE
READ_INTERNAL_STORAGE
Docs link here
Reference
The following changes have fixed the problem:
In the app.json
"android": {
"package": "br.com.miredefamilia",
"versionCode": 3,
"permissions": [
"CAMERA",
"READ_INTERNAL_STORAGE",
"WRITE_INTERNAL_STORAGE",
"READ_EXTERNAL_STORAGE",
"WRITE_EXTERNAL_STORAGE"
]
}
And the calls to the component, I removed the parameters:
const image = await ImagePicker.launchCameraAsync();
let image = await ImagePicker.launchImageLibraryAsync();
I also removed the dependency:
"react-native-camera": "^0.10.0",
I don't know exactly which one solved the problem, but one of them did.
Related
I have been working on a mobile app for the past year, and are preparing to deploy to production. Our app is used for sending applications for a certain license, and some users may be required to upload images in their application.
This feature has been implemented and working for many months, and given us no issues. However, now the Android version of the app is causing problems. When we submit the application, the fetch request to the endpoint is initiated, but never actually hits (only if images are included in the application).
Here is the code where the images are handled:
const xhr = new XMLHttpRequest()
xhr.responseType = 'blob'
xhr.onload = () => {
const file = xhr.response
const extension = file.type.split('image/').pop()
const fileName = `${field.identifier}-${docCounter}.${extension}`
if (Platform.OS === 'web') {
formData.append('filesToUpload', file, fileName)
} else {
formData.append('filesToUpload', {
uri: fileInfo.uri,
type: `image/${extension}`,
name: fileName,
})
}
//Other unrelated code
}
xhr.open('GET', url)
xhr.send()
Then the request:
const task = await fetch(
new Request(`${Constants?.manifest?.extra?.hostname}/ext/tasks`, {
method: 'POST',
}),
{
body: formData,
headers,
}
)
The headers just includes an authorisation token related to the user submitting the application.
So yeah, on web and iOS, this processes with no issue, but on Android, it starts the request, but never hits the endpoint.
Any help would be appreciated.
EDIT
I have been doing some debugging, and I think the issue is that the the file is not giving me a type from the blob, so in my formData type: 'image/${extension}', the extension does not exist.
So I logged the file object on both Android and iOS, and this is what I got.
iOS
{"_data": {"__collector": {}, "blobId": "1B56DE00-DDE9-494A-B57A-343040B6D12B", "name": "users_zw3GBtId4O0m0FAtpc94AUgBchPU_mutable_b293b904-6711-4384-a1c2-e540f5d6c1f8.png", "offset": 0, "size": 455495, "type": "image/png"}}
Android
{"_data": {"__collector": {}, "blobId": "11a2875e-903c-4f87-a997-7e31c7013cfb", "offset": 0, "size": 179757}}
So as yo can see, the iOS app is giving me more data, and also the extension of the file.
I still don't know why this is the case.
I recently updated several lines of code in a managed expo project, unrelated to the camera functionality. It still works fine on iOS, only Android does not work. I had released a previous version one month ago that worked well. When I revert back to the old commit from then, though, it also does not work on Android (iOS fine).
expo 44.0.6
expo-camera 12.1.2
react 17.0.1
react-native 0.64.3
There is no issue launching the camera, etc. Rather, the issue occurs at takePictureAsync, which hangs and then does not return anything.
const snapPic = async () => {
const { status } = await Camera.getCameraPermissionsAsync();
if (status != 'granted') {
alert('Please grant access to camera and retry.');
await Camera.requestCameraPermissionsAsync();
return;
}
const options = { quality: 0.1 };
const photo = await this.camera.takePictureAsync(options);
this.camera.pausePreview();
this.setState({imageSource: photo.uri});
};
<Camera style={styles.cameraBox} ref={ref => {this.camera = ref}} />
Please let me know what other information I can provide, if necessary. Thanks in advance!
Instead of pause preview method. Try it with skipProcessing to false inside option object
I have implemented the below given code to let user share my app. It works fine, but how can I know if the user actually shared my app or not? Because my app unlocks a certain feature if the user shares the app.
[Package used:- share_plus 3.0.4 ]
onTap: () async {
const _textShareUrl =
'https://www.youtube.com/watch?v=CNUBhb_cM6E&list=PLk6qkmrzOcdx5R4-UqI_jDPYsLWNnZ1dq&index=2';
await Share.share(
'Social share test\n\n$_textShareUrl');
Future.delayed(const Duration(seconds: 10), () {
setState(() => _share = true);
});
},
There is already an open issue:
https://github.com/fluttercommunity/plus_plugins/issues/386
I am trying to add google sign-in feature to my app. This is working fine with an android emulator but I am running the app in the real device it is not working. The problem is after the sign-in process google redirect to its own home page instead to app.
The step I follow.
Function I use to open google sign in page
const result = await Google.logInAsync({
androidStandaloneAppClientId: '131814552849-bi76mebb3eq5jsdergerdfh6werjd8udpen43.apps.googleusercontent.com',
scopes: ['profile', 'email'],
behavior: 'web
});
app.json
I used Google Certificate Hash (SHA-1) in certificateHash
"android": {
"package": "com.abc.mycompnay",
"permissions": ["READ_EXTERNAL_STORAGE", "WRITE_EXTERNAL_STORAGE"],
"config": {
"googleSignIn": {
"apiKey": "AIzaSyB6qp9VXGXrtwuihvna40F57xABKXJfEQ",
"certificateHash": "29FD8B159A28F2F48ED3283548NEBFC957F6821D"
}
}
}
google console setting
Client key
After sign in its end up with its own home page
I manage to fix it. below is what I did. I pass the redirectUrl in config
import * as AppAuth from 'expo-app-auth';
const result = await Google.logInAsync({
androidStandaloneAppClientId: 'myKey,
iosStandaloneAppClientId: 'myKey,
scopes: ['profile', 'email'],
behavior: 'web',
redirectUrl: `${AppAuth.OAuthRedirect}:/oauthredirect`
});
Open the gradle and change the redirect scheme
android {
defaultConfig {
manifestPlaceholders = [
appAuthRedirectScheme: 'com.example.yourpackagename'
]
}
}
Okay, I'll put this here since this cost me a ton of lifetime. If you happen to test it with an Android device: Make sure you have selected Chrome as default browser. Others might not redirect you correctly!
In app.json,
package name has to be as all small letters like com.app.cloneapp
I am using zo0r react-native-push-notification library.
For some reason, when i open the app for the first time after i installed it on the mobile device (iOS or Android) the token is returned as null.
PushNotification.configure({
onRegister: function(token) {
console.log( 'TOKEN:', token );
},
onNotification: function(notification) {
console.log( 'NOTIFICATION:', notification );
},
senderID: "YOUR GCM SENDER ID",
permissions: {
alert: true,
badge: true,
sound: true
},
popInitialNotification: true,
requestPermissions: true,
});
My question is, which is the best approach to get the token if the onRegister method returns token as null?
Do i have to recall this function in other screen of the app?
"react": "16.0.0-alpha.6",
"react-native": "^0.44.3",
"react-native-push-notification": "^3.0.1"
Thank you for your help,
Mikhi
I had same problem. I don't know why but PushNotification.configure does not work on iOS, so you should use
const fcmToken = await firebase.messaging().getToken();
if (fcmToken) {
// user has a device token
} else {
// user doesn't have a device token yet
}
instead of PushNotification.configure, (do not forget to use async if you use await), or another way:
firebase.messaging().getToken()
.then(fcmToken => {
if (fcmToken) {
// user has a device token
} else {
// user doesn't have a device token yet
}
});
And for Android, the method I sent o above does not work. But PushNotification.configure works. You should use PushNotification.configure to get tokens for android. You should check your SDK, firebase-messaging versions and should update your android studio because old version of Android studio does not suppport of new version firebase-messaging. After I did these things I got my tokens successfully on Android. If you have some troubles to update these things I can send you all details of versions and how to update them.
This problem was FCM.getAPNSToken() runs right after FCM.requestPermissions(), so application didn't get permissions for push notifications when method runs.
Change:
componentDidMount -> async componentDidMount
and
FCM.requestPermissions(); -> await FCM.requestPermissions();
This solution is https://github.com/evollu/react-native-fcm/issues/528