Sometimes I have app crashes. It's related with Cloud Storage. The app was crashed immediately after file upload.
Crash log:
Fatal Exception: NSInvalidArgumentException
0 CoreFoundation 0x19d3a498c __exceptionPreprocess
1 libobjc.A.dylib 0x19d0cd0a4 objc_exception_throw
2 CoreFoundation 0x19d3fa3f8 -[__NSCFString characterAtIndex:].cold.1
3 CoreFoundation 0x19d40375c -[__NSPlaceholderDictionary initWithObjects:forKeys:count:].cold.5
4 CoreFoundation 0x19d2915dc -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]
5 CoreFoundation 0x19d283470 +[NSDictionary dictionaryWithObjects:forKeys:count:]
6 AirWork 0x102ef75f8 +[RNFBStorageCommon getUploadTaskAsDictionary:] + 309 (RNFBStorageCommon.m:309)
7 AirWork 0x102efd044 __84-[RNFBStorageModule addUploadTaskObservers:appDisplayName:taskId:resolver:rejecter:]_block_invoke + 456 (RNFBStorageModule.m:456)
8 AirWork 0x102d7463c __50-[FIRStorageObservableTask fireHandlers:snapshot:]_block_invoke_2 + 211 (FIRStorageObservableTask.m:211)
9 libdispatch.dylib 0x19d071610 _dispatch_call_block_and_release
10 libdispatch.dylib 0x19d072184 _dispatch_client_callout
11 libdispatch.dylib 0x19d0241d0 _dispatch_main_queue_callback_4CF$VARIANT$mp
12 CoreFoundation 0x19d3223c4 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
13 CoreFoundation 0x19d31d3b8 __CFRunLoopRun
14 CoreFoundation 0x19d31c8bc CFRunLoopRunSpecific
15 GraphicsServices 0x1a7188328 GSEventRunModal
16 UIKitCore 0x1a13b26d4 UIApplicationMain
17 AirWork 0x1025cad68 main + 14 (main.m:14)
18 libdyld.dylib 0x19d1a7460
You have to follow the template, or we can't help
Same here.
Sometimes I have app crashes. It's related with Cloud Storage. The app was crashed immediately after file upload.
Click To Expand
#### `ios/Podfile`: - [ ] I'm not using Pods - [x] I'm using Pods and my Podfile looks like:
platform :ios, '10.0'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
target 'Odoori' do
# Pods for Odoori
pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector"
pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec"
pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired"
pod 'RCTTypeSafety', :path => "../node_modules/react-native/Libraries/TypeSafety"
pod 'React', :path => '../node_modules/react-native/'
pod 'React-Core', :path => '../node_modules/react-native/'
pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules'
pod 'React-Core/DevSupport', :path => '../node_modules/react-native/'
pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS'
pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation'
pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob'
pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image'
pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS'
pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network'
pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings'
pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text'
pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration'
pod 'React-Core/RCTWebSocket', :path => '../node_modules/react-native/'
pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact'
pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector'
pod 'ReactCommon/jscallinvoker', :path => "../node_modules/react-native/ReactCommon"
pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon"
pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'
pod 'QBImagePickerController', :path => '../node_modules/react-native-image-crop-picker/ios/QBImagePicker/QBImagePickerController.podspec'
pod 'GoogleIDFASupport', '~> 3.14.0'
pod 'ViroReact', :path => '../node_modules/react-viro/ios/'
pod 'ViroKit_static_lib', :path => '../node_modules/react-viro/ios/dist/ViroRenderer/static_lib'
use_native_modules!
end
#### `AppDelegate.m`:
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
@import Firebase;
#import "AppDelegate.h"
#import <ViroReact/VRTBundleURLProvider.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
BOOL enterVrImmediately = YES;
BOOL usingNgrok = YES;
if ([FIRApp defaultApp] == nil) {
[FIRApp configure];
}
if(enterVrImmediately) {
NSURL *jsCodeLocation = nil;
#ifdef DEBUG
if(usingNgrok) {
VRTBundleURLProvider *bundleProvider = [[VRTBundleURLProvider alloc] init];
jsCodeLocation = [bundleProvider jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
}
#endif
if(jsCodeLocation == nil) {
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
}
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"Odoori"
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];
}
return YES;
}
@end
Click To Expand
Sometimes I have app crashes. It's related with Cloud Storage. The app was crashed immediately after file upload.
**`react-native info` output:**System:
OS: macOS 10.15
CPU: (4) x64 Intel(R) Core(TM) i5-7500 CPU @ 3.40GHz
Memory: 597.55 MB / 12.00 GB
Shell: 3.2.57 - /bin/bash
Binaries:
Node: 12.12.0 - /usr/local/bin/node
npm: 6.12.0 - /usr/local/bin/npm
Watchman: 4.9.0 - /usr/local/bin/watchman
SDKs:
iOS SDK:
Platforms: iOS 13.1, DriverKit 19.0, macOS 10.15, tvOS 13.0, watchOS 6.0
Android SDK:
API Levels: 23, 26, 27, 28, 29
Build Tools: 27.0.3, 28.0.3, 29.0.0, 29.0.1, 29.0.2
System Images: android-25 | Google APIs ARM EABI v7a, android-28 | Google Play Intel x86 Atom, android-29 | Google APIs Intel x86 Atom, android-29 | Google Play Intel x86 Atom
IDEs:
Android Studio: 3.5 AI-191.8026.42.35.5900203
Xcode: 11.1/11A1027 - /usr/bin/xcodebuild
npmPackages:
react: 16.10.2 => 16.10.2
react-native: 0.61.2 => 0.61.2
npmGlobalPackages:
react-native-cli: 2.0.1
react-native-rename: 2.4.1
- **Platform that you're experiencing the issue on**:
- [ ] iOS
- [ ] Android
- [x] **iOS** but have not tested behavior on Android
- [ ] **Android** but have not tested behavior on iOS
- [ ] Both
- **`react-native-firebase` version you're using that has this issue:**
- `6.0.1`
- **`Firebase` module(s) you're using that has the issue:**
- `@react-native-firebase/storage`
- **Are you using `TypeScript`?**
- `No`
Thanks for adding more information @Brouilles - could you provide the code snippet that does the upload?
Yes sure. It's this code.
fcmUpload() {
if (this.state.messageImageSourceCrop != '') {
this.setState({ showLoader: true });
const metadata = { contentType: 'image/jpeg' }
var imageRef = null
var userid = ''
Util.MultiGetData([keys.id, keys.name, keys.username, keys.description, keys.avatar, 'local'], TAG)
.then((data) => {
userid = data[0][1]
var timeStamp = Math.floor(Date.now());
timeStamp = userid + '_' + timeStamp
//thumbnail
imageRef = storage().ref('/Thumbnails').child(timeStamp + ".jpg")
imageRef.putString(`${this.state.messageImageSourceCrop}`, 'base64', { contentType: 'image/jpeg' })
.then(uploadedFile => {
return imageRef.getDownloadURL()
})
.then(() => { return imageRef.getDownloadURL() })
.then((url) => {
if (this.state.videoUrl != '') {
var thumbUri = url
console.log("kk-> thumbUri-"+thumbUri)
console.log("kk-> this.state.videoUrl-"+this.state.videoUrl )
RNFS.readFile(this.state.videoUrl, 'base64').then(base64VideoString => {
const video_metadata = { contentType: 'video/mp4' }
const videoRef = firebase.storage().ref('/Videos').child(timeStamp + ".mp4")
console.log("kk-> videoRef -> "+videoRef)
// videoRef.put(this.state.videoUrl, video_metadata)
videoRef.putString(`${base64VideoString}`, 'base64', { contentType: 'video/mp4' })
.then(uploadedFile => {
return videoRef.getDownloadURL()
})
.then(() => { return videoRef.getDownloadURL() })
.then((url) => {
this.getAddress(url, thumbUri)
// PubSub.publish('updateuser');
}).catch(err => {
console.log(err)
this.setState({ showLoader: false });
});
});
} else {
var thumbUri = url
imageRef = firebase.storage().ref('/Images').child(timeStamp + ".jpg")
imageRef.putString(`${this.state.messageImageSourceCrop}`, 'base64', { contentType: 'image/jpeg' })
.then(uploadedFile => {
return imageRef.getDownloadURL()
})
.then(() => { return imageRef.getDownloadURL() })
.then((url) => {
this.getAddress(url, thumbUri)
}).catch(err => {
this.setState({ showLoader: false });
});
}
}).catch(err => {
console.log(err)
this.setState({ showLoader: false });
});
});
} else {
this.getAddress("")
}
}
messageImageSourceCrop
is a base64 string.
But the app don't crash on iPhone XS. But others (iPhone 6s, iPhone 7 Plus, 7 sure). Maybe RAM? The image in Base64 is too big?
iOS 13.1.3. I don't have device on iOS 12.
But the app don't crash on iPhone XS. But others (iPhone 6s, iPhone 7 Plus, 7 sure). Maybe RAM? The image in Base64 is too big?
Possibly. Try various image sizes?
I have just try it. Same with small images, it's crash sometimes (most of the time).
I use putString because with the following code imageRef.put(Platform.OS === 'ios' ? imagePath.replace('file://', '') : imagePath, { contentType: 'image/jpeg' })
(uri is the local path). I have the follow error on all devices Error: 'RNFirebase.Base64.fromData' failed: Unknown data type.
. Don't crash the app, but don't work.
Thanks.
If you need more information. I can help. Maybe, the code is not good? It's a simple conversion from the old version of RNFirebase. Tomorrow (France) I try on Android. I'll keep you informed.
Hello @igor-lemon
Have you find a solution?
I have the answer for Android soon. If it's working or not.
Hi guys,
Same issue here with the same config.
The app crashes when we upload pictures and videos from gallery or camera.
@igor-lemon Did you find a solution to workaround the issue?
Thanks a lot.
@Brouilles @FlrnOdr Hi guys! I don't know why you ask me about a solution. I just reported about the bug, I'm not RNFirebase dev.
Same problem here. The crash is only happening on older devices (like iPhone 6S, I've never seen it on my iPhone 11). My upload code is simpler:
const path = `/u/${firebase.auth().currentUser.uid}/${uuid.v4()}`;
const ref = firebase
.storage()
.ref()
.child(path);
const task = ref.putFile(localPath, {
cacheControl: 'public, max-age=31536000',
});
await task.then();
I downgrade to 5.5.6 and it's working. I did not find any other solution.
@Brouilles I downgraded lib to 5.x too.
I don't have a device to test on, but staring at code it looks like the only way this can happen is if storageMetadata
gets set to nil
here: https://github.com/invertase/react-native-firebase/blob/master/packages/storage/ios/RNFBStorage/RNFBStorageCommon.m#L302
Putting a guard around that should be easy, but the bigger question is, why is that only coming up as nil
on some older devices? I always set metadata on my file uploads, so it seems like there might be a race condition where the metadata is set asynchronously, and that condition only gets tickled on slower devices.
I could not replicate the crash in the simulator.
Also watch out with logging huge amounts of data... It puts a lot of stress on your application.
Also you should not send base64 data over the javascript core, it is not meant for that.
Rather send the location of the file.
:)
@unicornRainbows Like I said before:
I use putString because with the following code imageRef.put(Platform.OS === 'ios' ? imagePath.replace('file://', '') : imagePath, { contentType: 'image/jpeg' }) (uri is the local path). I have the follow error on all devices Error: 'RNFirebase.Base64.fromData' failed: Unknown data type.. Don't crash the app, but don't work.
@Brouilles putString is to put the string contents of a file, not a string file path. You should be using putFile
if you have a file path/uri: https://invertase.io/oss/react-native-firebase/v6/storage/reference/reference#putFile
I have the same issue: sometimes app crash after file uploaded (I upload two same images in a row for test) from local storage to cloud storage.
My code for uploading:
````
uploadImageWithProgressBar(image, progressCallback) {
// define file name
const fileName = this.imageName(image);
// set firebase image reference
let fileImageRef = this.imagesRef.child(fileName);
// init upload task
const uploadTask = fileImageRef.putFile(image.path, { contentType: image.mime });
return new Promise((resolve, reject) => {
let fullPath = '';
const unsubscribe = uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED, {
next: (snapshot) => {
// calculate upload progress in percent
const uploadProgress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
// report progress to callback
progressCallback(uploadProgress);
// check whether we finished uploading
if (snapshot.state === 'success') {
// compose image object
fullPath = snapshot.ref.fullPath;
}
},
error: (e) => {
log.error(e);
// unsubscribe from uploading task
unsubscribe();
// reject error
reject(e);
},
complete: () => {
// unsubscribe from uploading task
unsubscribe();
storage()
.ref(fullPath)
.getDownloadURL()
.then((url) => {
// add image properties
image = {
name: fileName,
// set download url
source: url,
};
// return new image object
resolve(image);
});
},
});
});
}
imageName(image) {
switch (image.mime) {
case 'image/jpeg':
return ${uuid.v1()}.jpg
;
case 'image/png':
return `${uuid.v1()}.png`;
default:
log.warn(`unknown mime type: ${image.mime}`);
return null;
}
}
async uploadImages() {
for (const image of [...this.images]) {
console.log('upload image');
await this.uploadImageWithProgressBar(image, (progress) => {
this.uploadProgress = progress;
});
console.log('upladed image');
}
````
What's happening:
console.log
message that image was uploadedconsole.log
message that second image is going to start uploadingError message from xcode:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[1]'
Steps to reproduce:
Device info:
iPhone XR (iOS 13.1.3, device)
iPhone 11 (iOS 13.2, simulator)
Ready to provide additional details.
p.s. part of package.json
dependencies regarding react-native-firebase
...
"@react-native-firebase/admob": "^6.0.3",
"@react-native-firebase/app": "^6.0.3",
"@react-native-firebase/auth": "^6.0.3",
"@react-native-firebase/dynamic-links": "^6.0.3",
"@react-native-firebase/messaging": "^6.0.3",
"@react-native-firebase/remote-config": "^6.0.3",
"@react-native-firebase/storage": "^6.0.3",
...
@zwily I got storageMetadata
set to nil
. After adding a check there, I don't see crash anymore.
RNFBStorageCommon.m (line 309)
return [@{
@"bytesTransferred": @(task.progress.completedUnitCount),
@"metadata": storageMetadata != nil ? storageMetadata : [NSNull null],
@"state": state,
@"totalBytes": @(task.progress.totalUnitCount)
} mutableCopy];
@r0b0t3d good find, can you send a quick PR for that? I can get it out in a patch release today if so. Thanks
@Salakar PR created #2875
Fix is now live in v6.0.4. Thanks
I still get this error if I upload a really long filename as ref ID. Solved by creating my own ID.
import storage from '@react-native-firebase/storage';
import React, {useState} from 'react';
import {
Alert,
Button,
Image,
ImageURISource,
StyleSheet,
View,
} from 'react-native';
import ImagePicker, {ImagePickerOptions} from 'react-native-image-picker';
import {Colors} from '../Styles';
import {ErrorBoundary} from './ErrorBoundary';
import {v4 as uuid} from 'uuid';
type StorageImageProps = {
onImage: (uri: string) => void;
};
export const StorageImage: React.FunctionComponent<StorageImageProps> = (
props,
) => {
const [image, setImage] = useState<ImageURISource | undefined>(undefined);
const [uploading, setUploading] = useState<boolean>(false);
const [progress, setProgress] = useState<number>(0);
const imageOptions: ImagePickerOptions = {
title: 'Select Image',
allowsEditing: true,
quality: 0.8,
tintColor: Colors.AccentMain,
cameraType: 'back',
storageOptions: {
skipBackup: true,
path: 'images',
},
};
const pickImage = () => {
ImagePicker.showImagePicker(imageOptions, (r) => {
if (r.didCancel) {
return;
}
if (r.error) {
Alert.alert('Could not select image', r.error, [
{text: 'Close', onPress: () => {}},
]);
return;
}
const imageSource: ImageURISource = {uri: r.uri};
console.log('Created image source', imageSource);
setImage(imageSource);
uploadImage(imageSource);
});
};
const uploadImage = async (imageSource: ImageURISource) => {
if (!imageSource || !imageSource.uri || uploading) {
console.log('Already uploading or no image', image);
return;
}
setUploading(true);
try {
console.log('Uploading image');
const newId = uuid();
// Extract image extension
const ext = imageSource.uri.split('.').pop();
// Generate a safe filename
const filename = `${newId}.${ext}`;
await storage()
.ref(filename)
.putFile(imageSource.uri)
.on('state_changed', async (snapshot) => {
if (snapshot.error) {
console.log('Upload failed', snapshot.error);
return;
}
const newProgress =
(snapshot.bytesTransferred / snapshot.totalBytes) * 100;
setProgress(newProgress);
if (snapshot.state === storage.TaskState.SUCCESS) {
console.log('Upload success!');
setProgress(0);
setUploading(false);
const liveUrl = await snapshot.ref.getDownloadURL();
setImage({uri: liveUrl});
props.onImage(liveUrl);
}
});
} catch (error) {
console.log('Upload failed', error);
setProgress(0);
setUploading(false);
}
};
return (
<ErrorBoundary>
<View>
{image ? (
<Image source={image} style={{height: 200, margin: 5}} />
) : null}
{uploading ? (
<View style={[styles.progressBar, {width: `${progress}%`}]} />
) : null}
<Button title="Pick image" onPress={() => pickImage()} />
</View>
</ErrorBoundary>
);
};
const styles = StyleSheet.create({
progressBar: {
backgroundColor: 'rgb(3, 154, 229)',
height: 3,
shadowColor: '#000',
margin: 5,
},
});
@thomashagstrom can you open a new issue, this one is approximately a year old? It would be especially helpful to have an example of an actual file name that crashes
Most helpful comment
@zwily I got
storageMetadata
set tonil
. After adding a check there, I don't see crash anymore.RNFBStorageCommon.m (line 309)