Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Events are not fired on Android #81

Open
kulyk opened this issue Apr 30, 2018 · 31 comments
Open

Events are not fired on Android #81

kulyk opened this issue Apr 30, 2018 · 31 comments

Comments

@kulyk
Copy link

kulyk commented Apr 30, 2018

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

@TSMMark
Copy link
Contributor

TSMMark commented Apr 30, 2018

Hi @antonkulyk thanks for reporting your issue. Please provide a minimal reproduction of the issue by forking the example app

@kulyk
Copy link
Author

kulyk commented May 1, 2018

Can't reproduce it on the example app 😞
Do you have any ideas what could go wrong?

@TSMMark
Copy link
Contributor

TSMMark commented May 1, 2018

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

@dmyur
Copy link

dmyur commented May 1, 2018

@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!

@StevePotter
Copy link
Contributor

@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.

@dmyur
Copy link

dmyur commented May 1, 2018

@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.

@sraka1
Copy link

sraka1 commented May 15, 2018

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 gotev/android-upload-service#374 and gotev/android-upload-service#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.

@sraka1
Copy link

sraka1 commented May 15, 2018

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.

@gotev
Copy link

gotev commented May 15, 2018

@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.

@sraka1
Copy link

sraka1 commented May 15, 2018

@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

@gotev
Copy link

gotev commented May 15, 2018

In native Android it doesn't make difference, but I don't know if in RN the two are treated differently.

@sraka1
Copy link

sraka1 commented May 15, 2018

@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!

@gotev
Copy link

gotev commented May 15, 2018

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.

@sraka1
Copy link

sraka1 commented May 15, 2018

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...

@gotev
Copy link

gotev commented May 15, 2018

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.

@sraka1
Copy link

sraka1 commented May 15, 2018

@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 :/

@gotev
Copy link

gotev commented May 15, 2018

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.

@sraka1
Copy link

sraka1 commented May 15, 2018

I'm pretty sure that somehow during the build, the AndroidManifest from android-upload-service is being ignored. And since there is then no definition, no service is started 😢

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...

@sraka1
Copy link

sraka1 commented May 15, 2018

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! 😮

@StevePotter
Copy link
Contributor

@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?

@gotev
Copy link

gotev commented May 16, 2018

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!

@sraka1
Copy link

sraka1 commented May 16, 2018

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 tags directly into their apps' AndroidManifest, so I don't think asking the users to do this would be a problem at all. So, yeah, @StevePotter I'd ask the users to do this...

@gotev
Copy link

gotev commented May 16, 2018

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

@brian-pitsch
Copy link

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

@EJohnF
Copy link
Contributor

EJohnF commented Jan 22, 2019

Hoping that a new comment will raise this issue up: I have the same problem, and manifest update didn't help

@adityasonel
Copy link

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?

@EJohnF
Copy link
Contributor

EJohnF commented May 11, 2019

I ended up with moving to pure XMLHttpRequest which works quite well

@nachumFreedman
Copy link

This is some sort of joke right?

@ahaus
Copy link

ahaus commented Sep 20, 2019

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

@Hamawis
Copy link

Hamawis commented Feb 7, 2020

Any update on this?

@uplsoumen
Copy link

Hello,
Any update?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests