Cancelling/Exiting Photo Library in Android using react-native-image-crop-picker - android

In my React Native app, I use the react-native-image-crop-picker package to have access to user's photo library.
It works nicely but if the user has no images in his/her photo library, I want to give the user a way to cancel out or exit it. How do I do that? Currently in Android, I click the element e.g. button or menu item to access user's photo library but then I get stuck there -- see image below:
And if I use gestures to get back to my app, I get the following warning.
Possible Unhandled Promise Rejection
My code is pretty basic at this point. When the user presses a button, I call this function which invokes the image picker:
pickImage() {
ImagePicker.openPicker({
width: 400,
height: 250,
cropping: true
}).then(image => {
onFilePicked(image);
});
}
Basically, I just need to give the user a way to cancel out of picking an image from the photo gallery. I'd appreciate some pointers on this. Thanks!

The npm package react-native-image-crop-picker is the most used library in react-native to choose Images and videos across the platforms.
It opens a default native Intent from which we can select media files from the gallery, We are not able to customize the view of it as its pure native intent is available into the native device.
And the error message Possible Unhandled Promise Rejection We get is the default error from the library, when the user goes back into our app without selecting a single image or video.
To handle the error message we have to wrap our code inside to try and catch it.
For Ex:
ImagePicker.openPicker({
width: 400,
height: 250,
cropping: true
}).then(image => {
onFilePicked(image);
}).catch(err => {
console.log('Error : ', err.message)
});
// - OR -
try {
const imagePickerRes = await ImagePicker.openPicker({
width: 400,
height: 250,
cropping: true
})
console.log('imagePicker Result : ', imagePickerRes)
} catch (err) {
console.log('Error : ', err.message)
}

Related

Expo Image Picker -- not returning image from Android Emulator in Android Studio

I am running the Pixel 5 API 30 avd in Android Studio with react native client coding.
I am using the expo image picker to pick the image and return to the application.
The code is :
const handleUpload = async () => {
//application needs to ask for permission
let permissionResult =
await ImagePicker.requestMediaLibraryPermissionsAsync();
// return;
if (permissionResult.granted === false) {
alert("Camera access is required");
return;
}
let pickerResult = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
aspect: [4, 3],
base64: true,
});
console.log(pickerResult);
if (pickerResult.cancelled === true) {
return;
}
// save to state for preview
let base64Image = `data:image/jpg;base64,${pickerResult.base64}`;
setUploadImage(base64Image);
// send to backend for uploading to cloudinary
};
It is all good -- I give permission and then have taken pictures with the android simulator to create an image bank on the emulator.
However, when I select the image -- expected behaviour is for the function to return to the caller and the image to be selected. All I can do is, however keep clicking the image randomly -- it doesn't seem to 'select' it and return.
Any suggestions?
Further info on the Expo image picker here:
https://docs.expo.dev/tutorial/image-picker/
thx!
Karen
You just need to select the crop (top right) -- as the code passing the option to 'allowEditing' --- to retun from the function.

React Native + Expo - Triggering an android intent to open locally stored files. (Android)

We've got a managed expo app, which is using the FileSystem.downloadAsync and this is all okay.
We've got a FlatList which is displaying a list of downloaded files.
We don't want to build in a file viewer, for every app under the sun, that's not the aim.
We want to be able to click a file from the list and potentially using the Android Intent system to offer the user a list of apps they already have installed which can handle the file type.
e.g. We've got something like
class FileBrowser extends Component {
state = {
files: [
{
key: '1'
name: 'file.jpg',
sys_path: 'file://blah.jpg'
}
]
}
openFile(item) {
IntentLauncherAndroid.startActivityAsync(
'android.intent.action.OPEN_DOCUMENT', {
data: item.sys_path
})
}
render() {
return (
<FlatList data={ this.state.files } renderItem={ (item) => <Button title={ item.name } onPress={ this.openFile(item) } />} />
)
}
}
We've pretty much exhausted the list of intents from https://chromium.googlesource.com/android_tools/+/febed84a3a3cb7c2cb80d580d79c31e22e9643a5/sdk/platforms/android-23/data/activity_actions.txt
The only one that almost gets there is android.intent.action.VIEW however that just opens a random list of apps, none of which can handle images - We've also passed in the mime type e.g. image/jpeg or image/* hoping that will filter the list.
What would be the correct way on Android only to offer the user to open the file in an appropriate apps?
with Expo SDK 34 (I use expo 34.0.3 because of there is font not resolve issues), you can do the open list as this way. but this is not a proper solution to open list. because the user has to do some work like this.
expo sharing api
await Sharing.shareAsync(
fileUri,
{dialogTitle: 'share or copy your pdf via'}
).catch(error =>{
console.log(error);
})
if you do this with providing a local file URI, you can see this bottom action sheet as below. then the user can choose the copy to option and paste it some location. after that user can open the file and then OS ask for what app will be used to open your file.

Ionic 3 Read URL as base64 in Android

I'm using the Ionic 3 Camera and File plugins to work with image selection from the user's Android gallery app. The plugin returns a file uri which I want to use to extract a base64 encoded image with the File plugin, but I get a NOT_FOUND_ERR when I attempt to read the file from the cache directory. Here's a sample of my code and some log outputs:
this.camera.getPicture(this.getCameraOptionsForPhotoLibrary()).then((fileUri: string) => {
const fileNameIndex: number = fileUri.lastIndexOf('/') + 1;
// file:///storage/emulated/0/Android/data/com.myDomain.myApp/cache/
const cacheDirectoryFromFileUri = fileUri.substring(0, fileNameIndex );
// FB_IMG_1532921240445.jpg?1532982282636
const fileName = fileUri.substring(fileNameIndex);
this.file.readAsDataURL(cacheDirectoryFromFileUri, fileName).then(base64 => {
alert('base64 cacheDirectoryFromFileUri success: ' + JSON.stringify(base64));
}, err => {
alert('base64 cacheDirectoryFromFileUri err: ' + JSON.stringify(err));
});
Please let me know I can provide any more information to help troubleshoot.
While trying to replicate your error I did not get a NOT_FOUND_ERR.
Although, this code block
this.camera.getPicture(this.getCameraOptionsForPhotoLibrary()).then((fileUri: string) => {
const fileNameIndex: number = fileUri.lastIndexOf('/') + 1;
// file:///storage/emulated/0/Android/data/com.myDomain.myApp/cache/
const cacheDirectoryFromFileUri = fileUri.substring(0, fileNameIndex );
// FB_IMG_1532921240445.jpg?1532982282636
const fileName = fileUri.substring(fileNameIndex);
this.file.readAsDataURL(cacheDirectoryFromFileUri, fileName).then(base64 => {
alert('base64 cacheDirectoryFromFileUri success: ' + JSON.stringify(base64));
}, err => {
alert('base64 cacheDirectoryFromFileUri err: ' + JSON.stringify(err));
});
}
gave me this error
base64 cacheDirectoryFromFileUri err: {"code":5,"message":"ENCODING_ERR"}
I was using these Options
{
quality: 100,
destinationType: this.camera.DestinationType.FILE_URI,
encodingType: this.camera.EncodingType.JPEG,
mediaType: this.camera.MediaType.ALLMEDIA,
sourceType: this.camera.PictureSourceType.PHOTOLIBRARY
}
The following line
const cacheDirectoryFromFileUri = fileUri.substring(0, fileNameIndex );
Gives me something like this
/storage/emulated/0/WhatsApp/Media/WhatsApp Images/
Upon changing that line to the following
const cacheDirectoryFromFileUri = 'file://'+fileUri.substring(0, fileNameIndex );
Solved the issue.
Or if you are trying to get the image from your cache after taking the image from your camera and want to get the base64 encoded string, you can use the Camera.DestinationType : DATA_URL
destinationType: this.camera.DestinationType.DATA_URL
I was unable to replicate Patra's answer the way it was described, but I did manage to extract some useful information through testing since I first posted.
In some cases I found if I remove the trailing digits after the ? (FB_IMG_1532921240445.jpg?1532982282636), the result was successfully returned. But this was conditional on a couple of device/configuration scenarios. For instance, it fails on Oreo on a Pixel 2 if I release an APK. In fact, it fails without the error callback being invoked, so I can't even handle the failure. But for some reason if I build from the CLI with the -lc flags on the same device, it will return the base64 result as intended.
When testing a 7.0 and 7.1 emulated device, it works as intended regardless of the build configuration.
It's a frustrating experience that the behavior is markedly different between devices and configurations. I'm especially curious about the livereload discrepancy, if anyone has any insight on why the file plugin behavior changes based on this flag it would be great to know.
I'm still trying to solve this, although apart from cracking open the plugin I'm not sure where to go. I have experimented with the Base64 Native Plugin which seems to work initially, but it doesn't seem to be actively managed and there are a lot of unresolved issues according to the github page. I may end up using a combination of the File and Base64 plugins to get what I need for now.
/** Update **/
A member of our team found the specific answer to our problem here:
https://forum.ionicframework.com/t/file-readastext-never-resolves/85375/24
If this link ever breaks, here is what we did to fix it:
Place cordova.js after polyfills.js in index.html
What a horrific bug.

Error: "Not allowed to load local resource" when using navigator.camera.getPicture()

I'm using Corodva 2.3.0 and an Android 2.3.3 virtual device. In my Cordova enabled app I am trying to take a picture and then have that picture display on the page. In my "Take Picture" button I am running the following code:
function takePicture()
{
navigator.camera.getPicture(displayPictureURI, showError, {
quality: 50,
destinationType: Camera.DestinationType.FILE_URI
});
}
function displayPictureURI(imageURI)
{
var imagePanel = document.getElementById('imagePanel').style.display = "";
document.getElementById("image").src = imageURI;
}
function showError(fail)
{
alert(fail);
}
The camera opens, I take a picture, and the app re-opens, but the picture is never displayed. In the log I get the following error: "Not allowed to load local resource: file:///mnt/sdcard/Android/data/org.apache.cordova.example/cache/1359468575251.jpg at :0"
I'm not sure what I am doing wrong here. I have the "WRITE_EXTERNAL_STORAGE" permission setup in the manifest. Any help is appreciated.
Isn't really a proper solution, but I have found that if I use an earlier version of Phonegap, this issue doesn't occur. It seems 1.7.0 works.

How to create a generic "create photo" code for both iPhone and Android using Appcelerator?

I am trying to create an application that is capable of creating photos on both Android and iPhone using Appcelerator. The functionality should launch default photo API, create a photo, allow user to either agree with photo, or cancel it, and on successful result save it on the memory card. It is not necessary that photos should be automatically added to the Gallery.
Currently I am using this code which works perfectly for Android :
Rf.media.photo = {
key: 'photo',
title: 'Photo',
extension: 'jpg',
type: 'image/jpeg',
create: function(created) {
Ti.Media.showCamera({
// TODO: disallow video for ios
animated: false,
saveToPhotoGallery: false,
showControls: true,
success: function(media_item) {
var name = Rf.util.timestamp() + '.' + Rf.media.photo.extension;
Rf.write_to_new_file(name, media_item.media, function(file) {
created(file);
});
},
});
},
};
I am looking for ways to tweek this code, so it would work also for iPhone. At the moment it is unresponsive when tested on iPhone 4.
Anyone knows whats wrong with it?
take a look at the kitchenSink examples for photo and photo gallery, they provide a pretty complete example

Categories

Resources