You might see that the Dropbox Community team have been busy working on some major updates to the Community itself! So, here is some info on what’s changed, what’s staying the same and what you can expect from the Dropbox Community overall.
Forum Discussion
NachoMurphy
8 years agoExplorer | Level 3
Dropbox Xamarin OAuth Flow Question - Retrieving the Access Token
Hi there, I have a mobile app on Android that uses Xamarin's tools to do some basic dropbox operations. In the past we used the Sync SDK to use dropbox quite easily. With the June v1 shut off comin...
Greg-DB
Dropbox Staff
Can you share the full error/output for the exception you mentioned?
We can't offer much help with anything Xamarin-specific, but we'll be happy to take a look and see what's going on with the Dropbox side of things.
Thanks in advance!
We can't offer much help with anything Xamarin-specific, but we'll be happy to take a look and see what's going on with the Dropbox side of things.
Thanks in advance!
NachoMurphy
8 years agoExplorer | Level 3
Thanks for your response Greg. I'm happy to share more info.
All I'm really after is grabbing the access token from the android browser and returning to my app in order to use it. There's just a disconect between when the user hits 'Allow' and when they return to my app. I can see the access token etc in the redirect URL, but it's unclear how I'd take that for use. When I use localhost as the redirect address, after Allow an app chooser appears and I can choose my app to use to go to. However, that's when the exception occurs.
The only error message I see in my output is :
Thread finished: <Thread Pool> #4 The thread 'Unknown' (0x4) has exited with code 0 (0x0). 05-09 08:33:25.048 D/AndroidRuntime(23519): Shutting down VM An unhandled exception occured.
It's not so much an specific exception, but seemingly nothing happens when the user gets redirected.
Here's what my ImageGallery activity code looks like that interacts with this:
private void HandleUpload () { // see if there is an existing user access token stored sp = GetSharedPreferences(SharedPrefsName, FileCreationMode.Private); AccessTokenValue = sp.GetString(AccessTokenKey, string.Empty); waitingOnDropboxUpload = true; if (AccessTokenValue.Equals(string.Empty)) { string authAddress = getOAuthAddress(); Intent browserIntent = new Intent(Intent.ActionView, Android.Net.Uri.Parse(authAddress)); StartActivityForResult(Intent.CreateChooser(browserIntent, "Open With"), 1); }
// continue with upload etc. } public static string getOAuthAddress() { string localRedirect = "https://localhost/"; var redirect = DropboxOAuth2Helper.GetAuthorizeUri( OAuthResponseType.Token, DropboxAppKey, localRedirect, AuthActivity.RandomString(16), true, false); string result = redirect.ToString(); return result; }
And of course the relevant manifest snippet:
<activity android:name="ImageGallery" android:launchMode="singleTask"> <intent-filter> <data android:scheme="db-<My_App_Key>" /> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.VIEW"></action> <data android:scheme="https" android:host="localhost"></data> <category android:name="android.intent.category.DEFAULT"></category> <category android:name="android.intent.category.BROWSABLE"></category> </intent-filter> </activity>
As I mentioned in the first post, per other forum advice I'm looking at the Java SDK and trying to emulate what that does. However it looks like as the comments in Auth.java & AuthActivity.java indicate, the auth flow used there is based on the SDK's OpenWith code for use with the official DropBox mobile app.
Now, I'm exploring using a WebView to keep everything inside my app for more control. Even then, I'll need to figure out how to grab the returned parameters from the redirect url. Thanks again for your help.
- NachoMurphy8 years agoExplorer | Level 3
I spoke too soon Greg, here's more exception details after I each time I get out of break mode:
05-09 09:01:00.418 E/AndroidRuntime(27739): FATAL EXCEPTION: main 05-09 09:01:00.418 E/AndroidRuntime(27739): Process: MyApp.App, PID: 27739 05-09 09:01:00.418 E/AndroidRuntime(27739): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{MyApp.App/MyApp.App.ImageGallery}: java.lang.ClassNotFoundException: Didn't find class "MyApp.App.ImageGallery" on path: DexPathList[[zip file "/data/app/MyApp.App-1/base.apk"],nativeLibraryDirectories=[/data/app/MyApp.App-1/lib/arm, /vendor/lib, /system/lib]] 05-09 09:01:00.418 E/AndroidRuntime(27739): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2236) 05-09 09:01:00.418 E/AndroidRuntime(27739): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387) 05-09 09:01:00.418 E/AndroidRuntime(27739): at android.app.ActivityThread.access$800(ActivityThread.java:151) 05-09 09:01:00.418 E/AndroidRuntime(27739): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303) 05-09 09:01:00.418 E/AndroidRuntime(27739): at android.os.Handler.dispatchMessage(Handler.java:102) 05-09 09:01:00.418 E/AndroidRuntime(27739): at android.os.Looper.loop(Looper.java:135) 05-09 09:01:00.418 E/AndroidRuntime(27739): at android.app.ActivityThread.main(ActivityThread.java:5254) 05-09 09:01:00.418 E/AndroidRuntime(27739): at java.lang.reflect.Method.invoke(Native Method) 05-09 09:01:00.418 E/AndroidRuntime(27739): at java.lang.reflect.Method.invoke(Method.java:372) 05-09 09:01:00.418 E/AndroidRuntime(27739): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) 05-09 09:01:00.418 E/AndroidRuntime(27739): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698) 05-09 09:01:00.418 E/AndroidRuntime(27739): Caused by: java.lang.ClassNotFoundException: Didn't find class "MyApp.App.ImageGallery" on path: DexPathList[[zip file "/data/app/MyApp.App-1/base.apk"],nativeLibraryDirectories=[/data/app/MyApp.App-1/lib/arm, /vendor/lib, /system/lib]] 05-09 09:01:00.418 E/AndroidRuntime(27739): at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56) 05-09 09:01:00.418 E/AndroidRuntime(27739): at java.lang.ClassLoader.loadClass(ClassLoader.java:511) 05-09 09:01:00.418 E/AndroidRuntime(27739): at java.lang.ClassLoader.loadClass(ClassLoader.java:469) 05-09 09:01:00.418 E/AndroidRuntime(27739): at android.app.Instrumentation.newActivity(Instrumentation.java:1066) 05-09 09:01:00.418 E/AndroidRuntime(27739): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2226) 05-09 09:01:00.418 E/AndroidRuntime(27739): ... 10 more 05-09 09:01:00.418 E/AndroidRuntime(27739): Suppressed: java.lang.ClassNotFoundException: MyApp.App.ImageGallery 05-09 09:01:00.418 E/AndroidRuntime(27739): at java.lang.Class.classForName(Native Method) 05-09 09:01:00.418 E/AndroidRuntime(27739): at java.lang.BootClassLoader.findClass(ClassLoader.java:781) 05-09 09:01:00.418 E/AndroidRuntime(27739): at java.lang.BootClassLoader.loadClass(ClassLoader.java:841) 05-09 09:01:00.418 E/AndroidRuntime(27739): at java.lang.ClassLoader.loadClass(ClassLoader.java:504) 05-09 09:01:00.418 E/AndroidRuntime(27739): ... 13 more 05-09 09:01:00.418 E/AndroidRuntime(27739): Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available
Hope this helps.
- Greg-DB8 years agoDropbox Staff
Thanks for the additional information!
If I understand correctly, you're using the API v2 .NET SDK, but you're trying to implement the app authorization flow the way the API v2 Java SDK does it. These two SDKs work differently though, so there will be a disconnect between the two. You won't be able to easily reconcile the two, so I recommend picking one or the other (whatever makes the most sense for your app/platform) and following the documentation/sample for the one you pick.
For reference, the Android app sample that uses the API v2 Java SDK uses a custom URL scheme as defined in the Manifest to directly receive the redirect after sending the user through the app authorization flow. Dropbox does some special handling for you to make use of that "db-<app_key>" URL scheme.
The API v2 .NET SDK on the other hand uses either the standard OAuth 2 'token' or 'code' flow. You can see how the code flow is initiated here and received here. There's a sample of initiating the token flow here (which your code so far uses) and receiving it here. I.e., you can use ParseTokenFragment to parse the token from the redirect URI.
(Also, I should note that you should no longer use web view for the OAuth app authorization flow, in order to support the embedded Google Sign In flow, as Google is no longer allowing their sign in flow to be processed in web views.)
In any case, the actual exception you're getting seems to be a ClassNotFoundException for class "MyApp.App.ImageGallery". That's not part of the Dropbox SDK though, and seems to just be part of your app, so I'm afraid I can't offer help with that in particular.
- NachoMurphy8 years agoExplorer | Level 3
Thanks for the response.
In light of the Web View news, I'm going to opt for only using the .NET SDK after all. It's true that I had been using parts of both SDKs before. It's frustrating because in the time between my posts I had implemented a WebView soution that was partially working. Oh well, so much for that.
Back to the issue then: I'm using the .NET approach to the OAuth flow. I use the android browser to navigate to the authorize URL. Then the user would sign in if needed and hit Allow. My newest issue then becomes: I get how the .NET SDK example uses BrowserNavigating to capture the event and can then parse the access token from the URI, but how would I do that for android? Is there a way to attach a listener to the browser intent? This is the immediate obstacle I'm facing at present.
Here's some revised code:
private void HandleDropboxOperation() { waitingOnDropboxUpload = true; taskCode = AuthActivity.RandomString(16); Toast.MakeText(this, "Uploading...", ToastLength.Short).Show(); //see if there is an existing user access token stored sp = GetSharedPreferences(SharedPrefsName, FileCreationMode.Private); AccessTokenValue = sp.GetString(AccessTokenKey, string.Empty); if (AccessTokenValue.Equals(string.Empty)) { this.OAth2State = Guid.NewGuid().ToString("N"); var authorizeUri = DropboxOAuth2Helper.GetAuthorizeUri(OAuthResponseType.Token, DropboxAppKey, new Uri(RedirectUri), state: Guid.NewGuid().ToString("N")); //no browser object available - use intent instead Android.Net.Uri.Builder b = new Android.Net.Uri.Builder(); b.AppendPath(authorizeUri.ToString()); Intent browserIntent = new Intent(Intent.ActionView, b.Build()); StartActivityForResult(Intent.CreateChooser(browserIntent, "Open With"), 1);
//below is from the .NET SDK code - how to implement in Android? //OAuth2Response result = DropboxOAuth2Helper.ParseTokenFragment(e.Uri);
//proceed with upload after token is obtained } else { InitiateUpload(); } }
About Dropbox API Support & Feedback
Find help with the Dropbox API from other developers.
5,910 PostsLatest Activity: 3 days agoIf you need more help you can view your support options (expected response time for an email or ticket is 24 hours), or contact us on X or Facebook.
For more info on available support options for your Dropbox plan, see this article.
If you found the answer to your question in this Community thread, please 'like' the post to say thanks and to let us know it was useful!