I'm using in my application a WebView which loads a Url can redirect to the Win. App store and therefore the OS opens the Win. store app on the device or open another 3rd party application for SMS\Email\etc.
I didn't find out yet how to know whether there's a redirect on the WebView using its callback functions such as NavigationStarting or NavigationCompleted, does anyone have an idea?
Thx!
you can use WebView.NavigationStarting event to get redirect url in webview.
XAML code:
<WebView x:Name="myWebView" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" NavigationStarting="myWebView_NavigationStarting" />
Code behind (C#):
private void myWebView_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args)
{
Uri uri = args.Uri;
if(uri.ToString() == "url you want to compare")
{
// work you want to do
}
}
Related
I've run into a problem using WebView to access the authorization uri necessary to authorize access by my Xamarin forms (running under iOS) app. I don't believe the problem lies with the WebView and the particular url, and not the Dropbox API itself.
First, I should mention that I am able to use WebView to access arbitrary web sites, so I know I am able to access the web generally from within my app.
In the code below you will see that I have two buttons set up. The first uses a WebView to successfully access the Wikipedia page for Xamarin. The second attempts to contact Dropbox in order to begin the authentication process. However, that request fails with the message:
Error (400) It seems the app you were using submitted a bad request. If you would like to report this error to the app's developer, include the information below. Invalid redirect_uri. Must be an absolute uri.
Initially, I thought that the problem was that the redirection uri wasn't registered correctly, but if I copy the url being passed to the webview (included below as a comment), and paste it directly into safari, the authentication page opens as expected. It is only when using WebView that I receive the error message. That makes me think that it's not the redirect_uri, or the url itself, but something in the way that the WebView is presenting it to dropbox.com.
Can anyone help me out? I've also tried taking a uri that works in Safari / Chrome and passing it directly to the webview (bypassing DropboxOAuth2Helper) without any luck. The uri will work in Safari, but not in the WebView.
public App()
{
Button xamarinBtn = new Button();
xamarinBtn.Text = "Xamarin";
xamarinBtn.Clicked += OnButtonClicked;
xamarinBtn.StyleId = "Xamarin";
Button dropboxBtn = new Button();
dropboxBtn.Text = "Dropbox";
dropboxBtn.Clicked += OnButtonClicked;
dropboxBtn.StyleId = "Dropbox";
StackLayout layout = new StackLayout();
layout.Children.Add(xamarinBtn);
layout.Children.Add(dropboxBtn);
ContentPage page = new ContentPage();
page.Content = layout;
MainPage = new NavigationPage(page);
}
private void OnButtonClicked(object sender, EventArgs e)
{
Button btn = sender as Button;
UrlWebViewSource source = new UrlWebViewSource();
if (btn.StyleId == "Xamarin")
{
source.Url = "https://en.wikipedia.org/wiki/Xamarin";
}
else if (btn.StyleId == "Dropbox")
{
string oauth2State = Guid.NewGuid().ToString("N");
Uri authorizeUri = DropboxOAuth2Helper.GetAuthorizeUri(OAuthResponseType.Token, "d1612up7la63slo", "http://127.0.0.1:52475/authorize", oauth2State);
source.Url = authorizeUri.AbsoluteUri; // https://www.dropbox.com/oauth2/authorize?response_type=token&client_id=d1612up7la63slo&redirect_uri=http%3A%2F%2F127.0.0.1%3A52475%2Fauthorize&state=1062a614aa3d4e2e85cd84de32903987
}
WebView webView = new WebView();
webView.Source = source;
ContentPage page = new ContentPage();
page.Content = webView;
MainPage.Navigation.PushAsync(page);
}
You should add that as a OAuth 2 redirect URI for your app via the App Console:
After doing this, I tried OC code it works properly and can show the authorize view. But Unfortunately, the Dropbox for Xamarin failed. You can try to use another api to show this view:
Uri authorizeUri = DropboxOAuth2Helper.GetAuthorizeUri("d1612up7la63slo");
source.Url = source.Url = authorizeUri.AbsoluteUri;
In my xamarin forms app, using webview I am loading a website with its IP. If the website loading is fail I want to redirect the user back to IP entering page and let him enter the correct IP. So how I can check the website is loading successfully or not?
Thanks in advance
In your shared project, you have the Navigated event from your Webview object:
WebView webView = new WebView ();
webView.Navigated += WebView_Navigated;
private void WebView_Navigated (object sender, WebNavigatedEventArgs e)
{
//your stuff
}
In the Flutter app I'm currently building, I need to authenticate users against a custom (so non-Google/Facebook/Twitter/etc) authorization server.
In order to achieve this, the users should fill in their credentials in a webpage. To this purpose, the WebView-plugin can be used. However, when the page is redirected after the user authenticated, the WebView should be closed, and the code passed on to the (Flutter) function that initially called the WebView.
Having done some research already, I came accross the following options:
This blog post uses a local server, which still requires the user to manually close the window, which is not a real solution (in my opinion).
This issue marks integration with any OAuth provider as done, but does not provide any details on the user authentication inside the browser.
This issue is exactly like I am describing, but at the bottom it is mentioned that the WebView plugin provides a way to close the WebView. While it does indeed have a close()-function, I cannot find a way to trigger it on the redirect-URI and return the verification code.
Does a solution exist, that closes the browser automatically once the redirect-URI is opened (and also returns the verification code)?
Thanks in advance!
I haven't tried this, but my idea is to use FlutterWebviewPlugin to send the user to a URL like https://www.facebook.com/v2.8/dialog/oauth?client_id={app-id}&redirect_uri=fbAPP_ID://authorize. Then add native handlers for application:openURL:options: (on iOS) and onNewIntent (Android) and modify AndroidManifest.xml and Info.plist to register the app to receive URLs from the fbAPP_ID scheme. You can use the platform channels to pass the deep link parameters back to Dart-land and call close() on the webview on the Dart side.
On request of #Igor, I'll post the code we used to solve this.
The idea is based both on the answer of #CollinJackson, and on how the AppAuth library does the same thing. Note: I don't have the iOS code here, but the code should be pretty trivial to anyone who regularly does iOS development.
Android-specific code
First, create a new Activity, and register it in the manifest to receive the URIs:
<activity
android:name=".UriReceiverActivity"
android:parentActivityName=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="organization" android:host="login.oauth2" />
<!-- Triggering URI would be organization://login.oauth2 -->
</intent-filter>
</activity>
In your Java-code, by default, there is one Activity (MainActivity).
Start a new MethodChannel in this activity:
public class MainActivity extends FlutterActivity implements MethodChannel.MethodCallHandler {
private static final String CHANNEL_NAME = "organization/oauth2";
public static MethodChannel channel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
channel = new MethodChannel(getFlutterView(), CHANNEL_NAME);
channel.setMethodCallHandler(this);
}
}
Note that this code is incomplete, since we also handle calls from this. Just implemented this method, and the method calls you might add. For example, we launch Chrome custom tabs using this channel. However, to get keys back to Dart-land, this is not necessary (just implement the method).
Since the channel is public, we can call it in our UriReceiverActivity:
public class UriReceiverActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Uri data = getIntent().getData();
Map<String, Object> map = new HashMap<>();
map.put("URL", data.toString());
MainActivity.channel.invokeMethod("onURL", map);
// Now that all data has been sent back to Dart-land, we should re-open the Flutter
// activity. Due to the manifest-setting of the MainActivity ("singleTop), only a single
// instance will exist, popping the old one back up and destroying the preceding
// activities on the backstack, such as the custom tab.
// Flags taken from how the AppAuth-library accomplishes the same thing
Intent mainIntent = new Intent(this, MainActivity.class);
mainIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(mainIntent);
finish();
}
}
This is heavily inspired by this code.
Now, the Flutter app is re-opened, and the URL (with token) is sent back to Dart-land.
Flutter code
In Dart, we have a singleton listening in on the channel (I'll only post fragments of the code, since it's not that nice and quite scattered around the file):
// Member declaration
_platform = const MethodChannel('organization/oauth2');
// Instantiation in constructor
_platform.setMethodCallHandler(_handleMessages);
// Actual message handler:
void _handleMessages(MethodCall call) {
switch (call.method) {
case "onURL":
// Do something nice using call.arguments["URL"]
}
}
On iOS, do the same as on Android, by sending the URL down the channel with that name and under the same command. The Dart code then doesn't need any changes.
As for launching the browser, we just use the url_launcher plugin. Note that we are not restricted to using a WebView, we can use any browser on the device.
Note that there are probably easier ways to do this, but since we had to make this quite early in Flutter's alpha, we couldn't look at other implementations. I should probably simplify it at some stage, but we haven't found time for that yet.
How can I detect mobile devices(but not tablets) requests in ASP.NET MVC application?
In ASP.NET, you can easily detect the mobile device request using Request.Browser.IsMobileDevice property and Request.UserAgent.
The following code checks the IsMobileDevice property and redirects to the mobile specific page:
protected void Page_Load(object sender, EventArgs e)
{
if (Request.Browser.IsMobileDevice)
{
Response.Redirec("~/default_mobile.aspx");
}
}
If you request "default.aspx" from mobile browser, it will redirect to default_mobile.aspx page
Read here where they explain in detail
Some times this may not work for some tablets
For that you have to use Request.Browser.ScreenPixelsWidth and validate against values of various screen sizes to achieve this . I think that will be the only way left to do it in the server side
If you want to trust client side javascript . There are varous scripts available to do that .
Check this Detect Mobile Browsers which may also help you .
As the other bloke said, you can use Request.Browser.IsMobileDevice
Either in your controller or in your layout page
Razor. You can do this in the layout page and it'll change depending on device e.g.
#if (Request.Browser.IsMobileDevice) {
}
Controller for an individual View e.g.
public ActionResult Index()
{
if (Request.Browser.IsMobileDevice)
return View("Index.Mobile");
else
return View();
}
An alternative is to use this API called 51Degrees.mobi. I personally haven't used it, but it looks pretty good and very complete: http://51degrees.codeplex.com/wikipage?title=MVC
Also, this has some more information on the subject of mobile detection. http://www.asp.net/whitepapers/add-mobile-pages-to-your-aspnet-web-forms-mvc-application
We are currently working on the finishing touches of an application which uses Phonegap and have hit some issues with the Blackberry port.
So far, we've been reviewing the content available online and can't find a really finale answer to this. Seems like the "right" way to make and oauth authentication process for either Twitter, Facebook or Foursquare would be to use the ChildBrowser plugin, instantiate a window and then use that to handle the process.
Rightly so, there seems to be a lack of a ChildBrowser plugin for Blackberry. We've been looking so far at a couple of private projects on Github that look like they build/use that capability but we are not sure on how to control the created window.
Most (or all?) of those plugins refer to invoking the native Blackberry browser to handle the URLS, but then how would be manage to work on the callbacks, get the tokens and close the windows since it's another process.
For example, we have this concept code:
function openWindow() {
if (typeof blackberry !== 'undefined') {
app_id = SOMETHING_HERE;
redirect = 'http://www.facebook.com/connect/login_success.html';
url = 'https://graph.facebook.com/oauth/authorizeclient_id='+app_id+'&redirect_uri='+redirect+'&display=touch&scope=publish_stream';
var args = new blackberry.invoke.BrowserArguments(url);
blackberry.invoke.invoke(blackberry.invoke.APP_BROWSER, args);
}
}
Which works for opening the URL, but that's it. Is there a way to get a handle on the window and inject some listener to events? What should be our correct approach?
Thanks!
I am not PhoneGap user, but we did have to handle a very similar scenario - native app invokes the mobile browser to prompt the oAuth flow and then be able to handle a callback to the aative app.
This is possible on the BlackBerry using the BrowserContentProviderRegistry API. You can register your app to be invoked whenever a particular MIME type is returned to the browser. Sounds complicated but its fairly straightforward when all the pieces are in play.
Here is the rough flow -
Native app invokes browser to the oAuth page. This is part is easy and seems like you got this part.
The oAuth redirect needs to go to a URL that you can control. Something like http://mycompany.com/oAuthRedirectHandler.asp.
The oAuthRedirectorHandler.asp has simple code like this (we chose classic ASP but this can be done in PHP or any language, you can also ignore the Android block below) -
<html><body>
<h1>Redirect page</h1>
If you are not re-directed, please open the application manually.
<% strUA = Request.ServerVariables("HTTP_USER_AGENT")
if (InStr(strUA, "BlackBerry")) then
Response.Write("Opening appplication on BlackBerry")
Response.ContentType="application/x-MyCustomApp"
elseif (InStr(strUA, "Android")) then
Response.Write("Opening appplication on Android")
Response.Redirect("MyCustomApp://mycompany.com")
end if %>
</body> </html>
In your BlackBerry code you want a new BrowserContentProvider like this -
final class CustomBrowserProvider extends BrowserContentProvider{
String[] ACCEPT = new String[]{"application/x-MyCustomApp};
String appName;
CustomBrowserProvider(String appName){
this.appName = ApplicationDescriptor.currentApplicationDescriptor().getModuleName();
//cache this appName from the constructor in the invocation code below.
}
public String[] getSupportedMimeTypes() { return ACCEPT;}
public String[] getAccept(RenderingOptions context){return ACCEPT;}
public BrowserContent getBrowserContent( BrowserContentProviderContext context) throws RenderingException {
//this is where the callback happens
//this is happening in a separate process, raise your main app here using the appName that got passed in
//I dont have a sanitized ready to go sample to post here on how to do this, but not too complicated
//as a hint use the ApplicationDescriptor and CodeModuleManager classes
return null;
}
}
Now, in your application initialization, register this new BrowserPlugin like this -
BrowserContentProviderRegistry converterRegistry = BrowserContentProviderRegistry.getInstance();
converterRegistry.register(new CustomBrowserProvider());
Hope this helps. This has worked pretty well for us. The one downside we've had here is that when the user returns to the browser app, they are left with an empty page and there is no good way to close that in the BB.