I have developed a browser(Xamarin App) named "MyBrowser" and now what I want is if a user clicks on any link it should open up a list of browsers (along with "MyBrowser") available for the user.
Once the user selects "MyBrowser", from there it should open the link in "MyBrowser".
If you're trying to catch all the web URLs such as the ones that start with http:// and https://, you can certainly do it on Android but on iOS it's not possible. I'll present a minimal example of how to catch the URL in your application, that should be a good starting point for you to move forward.
Android
On Android, you first need to decorate your main Activity with the IntentFilter attribute that defines the actions, categories and data schemes to utilize (this is basically the same as what you pasted to the comment section but in C#):
[Activity(Label = "UrlSample", MainLauncher = true)]
[IntentFilter(new[] { Intent.ActionView },
Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable },
DataSchemes = new[] { "http", "https" })]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
...
While the app is compiled, these attributes are parsed and inserted into the final AndroidManifest.xml file. For more information about the process and an example of this, take a look at Microsoft's documentation.
Now, you can check in the OnCreate method of MainActivity.cs, whether the app was launched via an appropriate Intent. MessageCenter will notify all the subscribers about an event called new_url (naming is up to you) with an instance of UrlMessage class as the payload and the Url set to a property within that class:
if (Intent != null && Intent.Action == Intent.ActionView)
{
Uri data = Intent.Data;
/* Get the full url with for example data.ToString() call and do whatever you want with it */
}
iOS
Unfortunately, Apple is not as permissive with the URL schemes as Android. In the official documentation, they state the following:
You cannot claim support for some well-known URL schemes, including http, https, mailto, tel, sms, facetime, and facetime-audio. The system directs well-known types of URLs to the corresponding system apps and well-known http–based URLs to specific apps, such as Maps, YouTube, and Music.
Related
I'm trying to authenticate an end-user in an android app written in C# (Xamarin.Android).
I decided to try and use NuGet package Google.Apis.Oauth.v2 which seems to expose an easy to use Oauth client.
LocalServerCodeReceiver.ReceiveCodeAsync throws the following:
I get System.NotSupportedException:"Failed to launch browser with https://XXX.auth.XXX.amazoncognito.com/login?response_type=token&client_id=XXX&redirect_uri=https%3A%2F%2Fwww.google.com&scope=profile%20openid%20email for authorization. See inner exception for details."
and it has an inner exception of System.ComponentModel.Win32Exception:"Cannot find the specified file"
Code:
var clientSecret = new Google.Apis.Auth.OAuth2.ClientSecrets();
clientSecret.ClientId = ...
clientSecret.ClientSecret = ...
var initializer = new Google.Apis.Auth.OAuth2.Flows.AuthorizationCodeFlow.Initializer(
"https://XXX.auth.XXX.amazoncognito.com/login",
"https://XXX.auth.XXX.amazoncognito.com/login");
initializer.Scopes = new List<string> {"profile", "openid", "email"};
initializer.ClientSecrets = clientSecret;
var flow = new Google.Apis.Auth.OAuth2.Flows.AuthorizationCodeFlow(initializer);
var authCodeRequestURL = flow.CreateAuthorizationCodeRequest("https://www.google.com");
authCodeRequestURL.ResponseType = "token";
var uri = authCodeRequestURL.Build();
var cancellationTokenSource = new System.Threading.CancellationTokenSource();
var codeReceiver = new Google.Apis.Auth.OAuth2.LocalServerCodeReceiver();
var task = codeReceiver.ReceiveCodeAsync(authCodeRequestURL, cancellationTokenSource.Token);
Do I need to ask for a specific permission in the application manifest?
Instead of redirecting to www.google.com, I've heard you can redirect to an app, I'm not really sure how to do that, is it http://my_app_package_name or http://my_app_title, something else?
Is it possible not to rely on that library for launching the browser and instead get the RequestUri and start an Activity, if so how will the app become aware the end-user completed the SignIn process and how will the app retrieve the token?
Sorry, but Google.Apis.Oauth.v2 does not support Xamarin, and there's no simple way to get it working.
Unfortunately no Google.Apis.* packages currently support Xamarin.
You might find the Xamarin.Auth package does what you want?
I've figured out how to redirect to an app after authentication in the browser completes.
It's called a "Deep Link" and it's documented at enter link description here, essentially you need to declare an IntentFilter on your Activity, which registers with the Android OS that if someone clicks or an page redirects to a specific URI, your app gets called. The token that's appended to the URI can then be read inside your app.
With normal installed apps it's possible to use the technique of Deep Linking in order to not only open a specific application from an URL but also to redirect it to a specific section/function such as a specific Facebook post or specific coordinates on a map.
Since I've read that with Instant Apps this won't be possible because links already point to the specific module to download and run, how would it be possible to access not only the said module but also pass it some parameters?
For example:
This is the link from which the view-only module of my map application will be downloaded: "www.myinstantappexample.com/onlyviewmap"
If I want it to point to a specific set of coordinates how would the link be composed?
Will it be like this: "www.myinstantappexample.com/onlyviewmap/?x=0.000&y=0.000" ?
From what I've been able to find google doesn't cover this aspect and I really can't wrap my head around it.
If I want it to point to a specific set of coordinates how would the link be composed?
It's up to you how to include any additional info in the URL. It could be via URL parameters or in the path itself. Eg.
https://www.myinstantappexample.com/location/2/user/5
https://www.myinstantappexample.com/onlyviewmap/?x=1.2&y=3.4
You then parse the URL in the receiving Activity. The Uri class includes a number of helper methods such as getQueryParameter() and getPathSegments() to make this easier.
For example, to parse this URL:
https://www.myinstantappexample.com/onlyviewmap/?x=1.2&y=3.4
You would do something like this in your Activity:
Uri uri = getIntent().getData();
String x;
String y;
if (uri != null) {
x = uri.getQueryParameter("x"); // x = "1.2"
y = uri.getQueryParameter("y"); // y = "3.4"
}
if (x != null && y != null) {
// do something interesting with x and y
}
Instant Apps and Deep Linking
Instant Apps rely on App Links to work, and App Links are just one type of deep link. So deep linking is still possible for Instant Apps, and is in fact absolutely critical to how they function. However, URI scheme deep linking (which is still very prevalent in Android apps) is not supported.
The difference between a regular app and an Instant App is that the device will only load a single Activity in response to the App Link the user clicks, instead of needing to download the full package through the Play Store. It's a more seamless experience for the user, but the underlying technology works the same way.
Passing Custom Parameters
If the user clicks an App Links-enabled URL like http://www.myinstantappexample.com/onlyviewmap/?x=0.000&y=0.000, you will get that entire string back inside the app after it opens. You'll have to parse out the x and y variables yourself, but they will be available to you. Something like this:
Uri data = this.getIntent().getData();
if (data != null && data.isHierarchical()) {
String uri = this.getIntent().getDataString();
Log.i("MyApp", "Deep link clicked " + uri);
}
You'll just need to manipulate the uri value to find what you need.
Alternative Approach to Custom Parameters
Alternatively, you can use Branch.io (full disclosure: I'm on the Branch team) to power your links. We have full support for Instant Apps, and this allows you to work with a much more friendly data format. We let you create links like this, to control every part of the behavior:
branch.link({
tags: [ 'tag1', 'tag2' ],
channel: 'facebook',
feature: 'dashboard',
stage: 'new user',
data: {
x: '0.000',
y: '0.000',
'$desktop_url': 'http://myappwebsite.com',
'$ios_url': 'http://myappwebsite.com/ios',
'$ipad_url': 'http://myappwebsite.com/ipad',
'$android_url': 'http://myappwebsite.com/android',
'$og_app_id': '12345',
'$og_title': 'My App',
'$og_description': 'My app\'s description.',
'$og_image_url': 'http://myappwebsite.com/image.png'
}
}, function(err, link) {
console.log(err, link);
});
In return you get a URL like http://myappname.app.link/iDdkwZR5hx, and then inside the app after the link is clicked, you'll get something that looks like this:
{
tags: [ 'tag1', 'tag2' ],
channel: 'facebook',
feature: 'dashboard',
stage: 'new user',
data: {
x: '0.000',
y: '0.000'
}
}
In order to do that, you have to use the "app links assistant" in
Tools->App Links Assistant
Then check your links and, in the Path selector, check that the "pathPrefix" option is selected.
Then at the bottom of the OnCreate method of your activity (which is related to the link you recently edited) add this code:
Intent appLinkIntent = getIntent();
String appLinkAction = appLinkIntent.getAction();
Uri appLinkData = appLinkIntent.getData();
// then use appLinkData.getQueryParameter("YourParameter")
You can test and debug this, using the "editConfigurations" option, just open that window and edit your instantApp module (the one launched with the Link you recently edited) and in the URL field add the URL parameters that you need. (then just run that module :D )
Hope this to be helpful.
I'm working on a game that runs on iOS, Android and Web. On the Web client I can set up a feed dialog that let's a user post on a friend's timeline:
That's achieved by using this code:
var params =
{
name: name,
link: link,
picture: picture,
caption: caption,
description: description,
actions: actions,
properties: properties
};
params.method = 'feed';
params.to = friend_id;
FB.ui(params, function(response){
...
});
The to field in the params is what makes the dialog select the friend's feed by default.
I want to do the same on the iOS and Android clients, but I can't find a way to achieve this with SDK 4.x.
The docs say:
"With the Share Button you will allow people to share content to their
Facebook timeline, to a friend's timeline or in a group."
Although it's true that the dialog allows the player to share on their friend's timeline, there doesn't seem to be a way to select this option before presenting the dialog to the user.
Looking at FBSDKShareDialog's and FBSDKShareLinkContent's interfaces I don't see a way to specify the "to" as we do in JS. Is this functionality just missing from the mobile SDKs?
So after some digging in the Facebook SDK's code I found a way to do what I wanted, but it's using undocumented and deprecated code... (according to the code comments this is there to support Unity). So it's not exactly recommended, but just in case it helps someone, here it goes:
On iOS, there's a hidden property in FBSDKShareLinkContent that lets you pass a free-form parameters dictionary for the share dialog in "feed" mode. Normally this is not accessible, but declaring an extension is all that's needed to make it public. Using the "to" key to specify the friend ID makes the dialog work as on the Web.
#interface FBSDKShareLinkContent ()
#property (nonatomic, copy) NSDictionary* feedParameters;
#end
...
FBSDKShareLinkContent* content = [[FBSDKShareLinkContent alloc] init];
content.contentTitle = title;
content.contentDescription = description;
content.contentURL = linkURL;
content.imageURL = imageURL;
content.feedParameters = #{#"to" : friendId}; // Setting hidden property
FBSDKShareDialog* shareDialog = [[FBSDKShareDialog alloc] init];
shareDialog.mode = FBSDKShareDialogModeFeedWeb; // Use feed mode
On Android, there's an undocumented class called ShareFeedContent that can be used instead of the normal ShareLinkContent and contains a toId field which is what I needed.
import com.facebook.share.internal.ShareFeedContent; // Import undocumented class
ShareFeedContent content = new ShareFeedContent.Builder()
.setLinkName(title)
.setLinkDescription(description)
.setLink(linkURL)
.setPicture(imageURL)
.setToId(friendId)
.build();
ShareDialog shareDialog = new ShareDialog(activity);
shareDialog.show(content, ShareDialog.Mode.FEED); // Use feed mode
It's probably not a good idea to use these, but they do definitely work. Hopefully someone else has a cleaner alternative.
I'm working on a Xamarin Forms application. It has an Entry field for the visit code on the initial page. I need to extend its functionality so that the application will open when a custom url scheme myscheme://visitcode is encountered, and the Entry will have its Text value prepopulated with the value of visitcode.
I've had success with getting the application to launch.
I added my scheme to the info.plist file in my iOS project, and it properly launches the app when I click on my custom url scheme in Safari on an iPhone.
I added the following line above my MainActivity in my Droid project:
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable }, DataScheme = "myscheme")]
It properly launches the app when I click on my custom url scheme in Chrome on an Android phone.
The only remaining obstacle is to retrieve the value and populate the Entry field with it.
Can someone help me?
Note: I haven't tested this yet, so make sure your app lifecycle and the place where you handle the events are matching the Xamarin.Forms app lifecycle. That is, make sure Xamarin.Forms.Application.Current is not null. If it is, reshuffle your code to work around that.
For iOS, you have to override OpenUrl in your AppDelegate.cs:
public override bool OpenUrl (UIApplication application, NSUrl url, string sourceApplication, NSObject annotation);
and in Android, you handle that in your MainActivity.cs, in your OnCreate or any other method used as entry point:
var intent = Intent;
var uri = intent.Data;
That should allow you to retrieve the parameters of the url.
You then can retrieve the current Xamarin.Forms Application object, by doing:
var myapp = Xamarin.Forms.Application.Current as MyApplication;
Now, it's up to you to retrieve the right entry, or it's view model, or a service or whatever to connect the dots.
There is a component within the Xamarin store that handles this for you:
http://components.xamarin.com/view/rivets
This will remove the lengthy code requirements in building native implementations.
I want to link to my App (made with Xamarin Android) from an email. This works. When I open the link in gmail, the app is opened indeed. However, when using another well known mail client (such as Outlook or Android Email) the situation is different. It tries to browse to the link instead of opening my app.
Here is my html (of the mail):
<a href="http://testje1.mywebdomain.net" style="text-decoration:none;color:#fff;background-color:#5bc0de;border-color:#46b8da;display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px"
role="button">HTTP</a>
<a href="ftp://testje2.mywebdomain.net" style="text-decoration:none;color:#fff;background-color:#5bc0de;border-color:#46b8da;display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px"
role="button">FTP</a>
<a href="doe://testje3.mywebdomain.net" style="text-decoration:none;color:#fff;background-color:#5bc0de;border-color:#46b8da;display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px"
role="button">doe</a>
In gmail, the "ftp" link directly links to my app. The "http" link asks if my browser needs to be opened or my app. The "doe" link does not work (which is no problem).
Here is my C# code with intent filters:
[Activity(Label = "MultiLinks", MainLauncher = true, Icon = "#drawable/icon")]
[IntentFilter(new[] { Android.Content.Intent.ActionView },
DataScheme = "http",
DataHost = "testje1.mywebdomain.net",
Categories = new[] { Android.Content.Intent.CategoryDefault })]
public class MainActivity : Activity
[Activity(Label = "SecondActivity")]
[IntentFilter(new[] { Android.Content.Intent.ActionView },
DataScheme = "ftp",
DataHost = "testje2.mywebdomain.net",
Categories = new[] { Android.Content.Intent.CategoryDefault })]
public class SecondActivity : Activity
[Activity(Label = "ThirdActivity")]
[IntentFilter(new[] { Android.Content.Intent.ActionView },
DataScheme = "doe",
DataHost = "testje3.mywebdomain.net",
Categories = new[] { Android.Content.Intent.CategoryDefault })]
public class ThirdActivity : Activity
How can I link to my app from an email and make it work in another email app than Gmail?
According to the documentation, you need to add the Browsable Category to your IntentFilter if you want a webbrowser to be able to launch your app:
https://developer.android.com/training/app-indexing/deep-linking.html#adding-filters
Include the BROWSABLE category. The BROWSABLE category is required in
order for the intent filter to be accessible from a web browser.
Without it, clicking a link in a browser cannot resolve to your app.
The DEFAULT category is optional, but recommended. Without this
category, the activity can be started only with an explicit intent,
using your app component name.
Hence your categories should look like:
Categories = new[] { Android.Content.Intent.CategoryDefault,
Android.Content.Intent.CategoryBrowsable }
So when another client launches a web browser, the web browser should be able to find out that the link actually belongs to an installed app.
The Chrome browser also supports special url's which can launch an Intent directly or show the play store page if the Intent is not present on the device.
It could look like:
intent://myApp/#Intent;scheme=myScheme;package=my.awesome.package.name;S.browser_fallback_url=http%3A%2F%2Fmyapp.com;end
More about that here: https://developer.chrome.com/multidevice/android/intents