react-native-background-upload
react-native-background-upload copied to clipboard
Events are not fired on Android
Hi, I need to upload files to Amazon S3 in my app. Everything works fine on the iOS, but I have some troubles with Android.
Here is the example
Upload.startUpload({
url: upload_url,
method: 'PUT',
path: Platform.OS === 'ios' ? path : path.replace('file://', ''),
headers: {
'Content-Type': mimeType,
'Content-Length': size + '',
},
}).then(uploadId => {
Upload.addListener('progress', uploadId, console.log);
Upload.addListener('error', uploadId, console.log);
Upload.addListener('cancelled', uploadId, console.log);
Upload.addListener('completed', uploadId, console.log);
}).catch(err => {
console.log('Upload error!', err);
});
For some reason, none of the progress
, error
, canceled
and completed
events are not fired after the upload starts. I get an uploadId
and nothing happens after that.
I've tried manipulating the SDKs versions (from this issue as well), upgrading React Native to the latest release, scanning the adb logcat. I've even put logs in the library's Java startUpload
method, but everything seems to be fine. Do you have any idea what could go wrong? Perhaps your library has conflicts with another lib?
React Native version: 0.52.0 react-native-background-upload version: 4.4.0 Devices: OnePlus 5 with Android 8 and 8.1, Google Pixel 2XL emulator with Android 7.x
Hi @antonkulyk thanks for reporting your issue. Please provide a minimal reproduction of the issue by forking the example app
Can't reproduce it on the example app 😞 Do you have any ideas what could go wrong?
I'm really not sure. I would start by stripping out functionality in your project until it's as close as possible to a minimal example which you have found to work. For example, maybe you would have better luck with a POST request rather than PUT, or maybe update the event handler callbacks (maybe an issue with the context the console log function is called with why passed in by reference? 🤷♂️ )
Upload.addListener('progress', uploadId, ({ progress }) => { console.log(`Progress: ${progress}%`) })
Sorry I can't provide any more information. Maybe @StevePotter would some ideas when he is available
@TSMMark Hi there, I am fighting with that issue together with Anton. We have covered UploaderModule.java
with logs and it looks like everything works fine until
String uploadId = request.startUpload();
It gives back uploadId
and successfully resolves the promise promise.resolve(uploadId);
.
Though
public void onProgress(Context context, UploadInfo uploadInfo);
in UploadStatusDelegate
is never called.
We checked if the passed file path is correct:
String filePath = options.getString("path");
...
File testFile = new File(filePath);
if (testFile.exists()) {
Log.d(TAG, "FILE EXISTS");
} else {
Log.d(TAG, "FILE DOES NOT EXIST");
}
And the file path passed appears to be valid.
It looks like request.startUpload
stays suspended from the very beginning.
Any ideas on what might went wrong are very very welcome. Thanks!
@antonkulyk and @diurchenko, thanks for writing. To be clear, you set a breakpoint in Android Studio on onProgress
and onError
in UploaderModule.java
here and it never hits? But the promise does resolve?
Can you check logcat for any other possible tracing info? Also, can you use the Network Profile and see if you can track down the request to S3?
Try not to get discouraged. Keep using the Android Studio tools and you'll get to the bottom of it. I would avoid messing with Javascript because this seems like a very platform-specific issue.
@StevePotter Hi Steve! That wasn't a breakpoint, but Log.d
before sending the event to JS sendEvent("progress", params)
. Thanks for your suggestions 💪. None of us is a java developer, but I'll try to dig deeper in Android Studio and will check Network Profile. Will get back here with more info.
Also experiencing this issue.
@StevePotter setting breakpoints on the delegate methods confirm they aren't being called. I suspect that either gotev/android-upload-service is buggy or being misconfigured.
Looking at https://github.com/gotev/android-upload-service/issues/374 and https://github.com/gotev/android-upload-service/issues/344 they mention that if you switch activities, the delegate method does not work and they recommend the broadcast receiver method.
From android-upload-service's wiki: If you set the delegate inside an activity, pay attention to its lifecycle, e.g. if you create a request with a delegate inside an activity and then you close it, the request will run in the background, but no callback methods will be invoked, because the delegate has been created inside the activity, which no longer exists. Delegates works best when used inside a service or an activity from which the user never goes away during the entire upload process. If this is not your case, I suggest you to use one of the following approaches.
Hm...I tried to implement the broadcast receiver into the library and that also wasn't triggering. Also I can do a cancelUpload successfully a long time after doing a startUpload, so the fact that none of the delegates/broadcast listeners/global listeners (listening mechanisms from gotev/android-upload-service) are triggering, leads me to believe that startUpload isn't even starting successfully.
I have confirmed this by monitoring incoming requests - when calling startUpload no requests are actually triggered. Thus, it seems fair to conclude that the problem lies not within the monitoring of the requests (delegates), but rather in the triggering of the request itself. String uploadId = request.startUpload();
returns an uploadId successfully, but does nothing! I suspect this is somehow a problem with the RN bridge and the Context it provides to gotev/android-upload-service.
I also tried updating to the latest version of android-upload-service
to no avail.
It almost seems like https://github.com/gotev/android-upload-service/blob/877ec555cb0ebd9a03dee8caa8813153ce7dfa11/uploadservice/src/main/java/net/gotev/uploadservice/UploadRequest.java#L76 is not starting the service correctly or it is not calling onStartCommand
as it's supposed to (https://github.com/gotev/android-upload-service/blob/877ec555cb0ebd9a03dee8caa8813153ce7dfa11/uploadservice/src/main/java/net/gotev/uploadservice/UploadService.java#L251).
@gotev Sorry to drag you in to another projects' issue, but do you have any idea why any of the commands in the startUpload->context.startService->onStartCommand chain would not be successful?
In any case, I'm giving up on using this library for now, as it's taken quite a lot of time to debug already, to no avail. Really hoping for some good feedback to this comment.
@sraka1 I think the problem has to be inspected at RN bridge level, because the service works successfully in production on all Androids and no errors like this ever happened. I encourage you to try the upload service demo app in the same environment in which you start your RN app and it should work. Adjust it with your custom parameters so it can make the same request to your backend.
The startUpload
method simply fires an intent, and all the other stuff which triggers the service is pure native Android SDK. If the service does not get triggered at all, maybe there's something in the RN context which gets passed down the line. Check if it's the current activity context or the application context to start with. Then, once you make the demo app work, inspect it with Android Studio step by step. Then do the same with the RN app and I'm sure you will get some insights. If it's an RN bug, with this kind of analysis you can ask for help by RN devs, which could replicate the issue you are facing and help you better than me.
Be sure to enable library debug log in all your tests, so you will get very verbose and detailed step by step logs which can help you debug.
@gotev Thanks for the reply.
The request gets passed the application context. That's not an issue is it? You wrote to check whether the application or current activity context is passed in, I thought that's irrelevant, isn't it?
cc @TSMMark
In native Android it doesn't make difference, but I don't know if in RN the two are treated differently.
@gotev Yeah, I figured. Btw, I'm not an Android dev, but is the <service android:name=".servicename"></service>
definition for services not necessary anymore in the AndroidManifest.xml?
I debugged this thing a bit further and I get a com.upload.uploadservice.action.upload
(yes, my app ID is com.upload
🤓 ) generated by intent.setAction(UploadService.getActionUpload());
However, the onCreate
method of the UploadService
is never called, so the service isn't even instantiated. Some older StackOverflow issues mention things like caps or spelling mistakes in the service definition in the AndroidManifest...but there doesn't seem to be a need for that definition at all anymore? Thanks again for your help so far!
You don't need to add any service declaration in your manifest. Just follow the getting started wiki page and make sure you set your package ID correctly by following the example.
Okay, I tracked down the issue (but no fix yet). Context.startService (https://developer.android.com/reference/android/content/Context.html#startService(android.content.Intent)) - specifically here - returns a ComponentName OR null - to quote the docs if the service does not exist null is returned.
. In my case, null
is indeed returned when calling startService
. But I have absolutely no idea yet as for why this intent fails to properly resolve to the service (the service not being found). Ideas/thoughts very welcome :)
P.S.: @gotev might be nice to check for that null
in that part of the code - because now it is failing silently...
In normal conditions in a fully native app, if you don't configure the namespace correctly it simply won't start and the solution is in the getting started wiki. Post the code you are using to initialize the library and the full package string of your app. You said you are using broadcast receivers. Post that code as well.
@gotev you mean the "Hey dude, please set the namespace" thing? That exception isn't thrown, as the NAMESPACE actually is set to the name of the app, as it's supposed to be (see also the actual implementation).
Nonetheless, the service is not started (null
returned on startService
call, as mentioned earlier). The full package string of my app is "com.upload". The full action name returned by getActionUpload in my case is then "com.upload.uploadservice.action.upload".
Broadcast receivers vs. delegates in this casedoesn't matter, as the core (the UploadService mentioned in the Developer's Manual isn't started at all :/
The last thing you should try is the upload service demo app with your same settings. I bet that null is because of something done by RN unless proven otherwise.
I'm pretty sure that somehow during the build, the AndroidManifest from android-upload-service is being ignored. And since there is then no
I will try now with the upload service demo app, but I'm also quite sure it will work...it's probably something with how RN does the Android build...
Woohoo, finally found the problem! 🎉
I needed to add the following to my apps AndroidManifest.xml
<service
android:name="net.gotev.uploadservice.UploadService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="${applicationId}.uploadservice.action.upload" />
</intent-filter>
</service>
The intent filter is not really super-necessary, but you might get warnings while building. This is to prevent other apps of starting this service, I guess...
@gotev It looks like the RN build process was not merging in the AndroidManifest.xml from your package! 😮
@gotev thanks so much for helping out, much respect! @sraka1 so should we just add that to the installation instructions? I wonder if we can somehow make this automatic. What do you think?
If RN is not merging manifests, it can be a problem. Nowadays all the libraries on Android rely on the Gradle manifest merger to avoid having to mess around with your manifest. Reach out the RN guys and let them know about it, maybe they already have a solution for this.
@StevePotter you're welcome!
I guess it might be because here the AndroidManifest is two layers below the app one?
App AndroidManifest->react-native-background-upload AndroidManifest->gotev/android-upload-service AndroidManifest... Usually (on native Android apps) you link with gotev/android-upload-service directly so I guess the merge works fine. Maybe it doesn't work well recursively (I'm not familiar in the logic of how gradle merges these, had a quick look into Merge Multiple Manifest Files but couldn't find anything relevant. @gotev
In any case, the fix I mentioned above works great :)
P.S.: I've seen other react-native libraries asking users to add
On native Android even multiple nested project's manifests are merged by Gradle without problems. So RN has that limitation and you have to tell users to manually add things into their manifests
I'm experiencing the same issue on 5.0, react-native 0.56 I've tried the AndroidManifest.xml addition mentioned above, but it didn't seem to do anything. However, I'm not sure if I'm putting it in the right part of the file. Where exactly in the file should it go? Directly inside the 'manifest' tags, 'application', or elsewhere? Thanks for any help
Hoping that a new comment will raise this issue up: I have the same problem, and manifest update didn't help
Hey guys,
In my case, I don't have to add service in the AndroidManifest.xml. File is correctly uploading but the react-native events is just hunted up on some point and then I don't know what is happening?
For example, I tried to upload 3MB picture multiple times sometimes it upload and I am getting event on react-native side. But sometimes events is just hanging up no call-backs for progress or completed or error or anything else.
I don't know what to do now?
I ended up with moving to pure XMLHttpRequest which works quite well
This is some sort of joke right?
To get upload events I had to use the Notification Object and set enabled=true for Android >= 8. (Still on version 4.4.0, RN 0.59.10).
...
this.notificationEnabled = Platform.OS != 'ios' && Platform.Version >25; // 26: 8.0, 27: 8.1
Any update on this?