Xamarin IOS custom URL Scheme not working in iOS 14 - ios

I created a Xamarin forms application and configured custom URL Scheme for iOS but it didn't fire in iOS 14.
So I created a sample native iOS project and test custom URL Scheme and it is working.
This is the sample iOS swift code.
import SwiftUI
#main
struct TestApp: App {
//#UIApplicationDelegateAdaptor var delegate: AppDelegate
var body: some Scene {
WindowGroup {
ContentView().onOpenURL(perform: handleURL)
}
}
func handleURL(_ url: URL) {
print("source application")
print(url)
}
}
But how can I convert this same to Xamarin. Because how to call onOpenURL in Xamarin iOS?

Add info about your custom scheme in your info.plist. You can do this in your iOS Project Options:
Double-click your iOS project >> Build > iOS Application >> Advanced (tab)
At the bottom, you'll see a section URL Types. Add your info about your custom scheme there. For example:
In the "Identifier" field, enter "com.myapp.urlscheme". In the "URL Scheme" field, enter "myapp".
Next you need to override in your AppDelegate file:
public override bool OpenUrl (UIApplication application, NSUrl url, string sourceApplication, NSObject annotation)
{
// custom stuff here using different properties of the url passed in
return true;
}
Go ahead and set a breakpoint on "return true" in the override above
Now if you build and run on the simulator, then enter "myapp://com.myapp.urlscheme" into the url bar in Safari (on the simulator), it should launch your app, hit your breakpoint, and the "url" param will be "myapp://com.myapp.urlscheme".

Related

Why does OpenUrl() is not being called in iOS 13 but it does in iOS 12.(Xamarin.ios)

We are working in xamarin.ios native app development. We have implemented OAuth redirect and implement OpenUrl() in AppDelegate class. it is working in iOS 12 but does not working is iOS 13 or later version both real device and simulator.
public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
{
// Convert iOS NSUrl to C#/netxf/BCL System.Uri - common API
var uri_netfx = new Uri(url.AbsoluteString);
clsXamrinAuthSample.Auth.OnPageLoading(uri_netfx);
return true;
}
we need some help.
From iOS 13 , you need to detail with openUrl in SceneDelegate.cs file , writing code in OpenUrlContexts method .
I am unable to access Url property.
About accessing Url proerty , you can get it from AnyObject element as follow .
[Export("scene:openURLContexts:")]
public void OpenUrlContexts(UIScene scene, NSSet<UIOpenUrlContext> urlContexts)
{
Console.WriteLine("URL property =====" + urlContexts.AnyObject.Url);
var urlString = urlContexts.AnyObject.Url;
if( urlString.Equals("wide://"))
{
// Run code
}
}

Opening an app from another app - "This app is not allowed to query for scheme"

I am unable to find a clear, precise guide on how to open another custom app from my current custom app.
I keep getting this error:
This app is not allowed to query for scheme myScheme.
I managed to get this working by doing the following:
In the below example the master app is the main app where I want to click a button and open another app. The other app in this example is called app2.
Both of the apps must belong to the same scheme to prevent the above "not allowed" error.
In the below example the scheme is called myapps but it can be anything you set it to in the Info tab (explained below).
In app2:
Click on your app Target (click your app name in the the heirarchy on the left then click your app name under TARGETS).
Click Info tab and scroll down to URL Types.
Click the arrow to expand URL Types, click the + to add a new entry.
Enter a unique identifier in the identifier field (I just used the bundle ID for that app... e.g com.mycompany.app2.
In the URL Schemes field, enter a name for your URL Scheme. In this example we shall call it myapps so we enter myapps into the field. This scheme name will need to be setup in the master app. For each additional app you want to open you need to setup a different scheme name and then also add the scheme name into the master app.
In the master app:
Repeat steps 1 to 5 - the only change will be step 4 as the unique identifier will be different and step 5 if you are setting up multiple apps.
Setup a button.
Connect the button to an action like below:
#IBAction func pressOpenAnotherApp(_ sender: Any) {
openApp(appURL: "myapps://com.companyname.app2"
}
Setup the openApp function:
func openApp(appURL: String) {
let openApp = URL(string: appURL)!
if UIApplication.shared.canOpenURL(appURL) {
UIApplication.shared.open(appURL, options: [:], completionHandler: { (success) in
print("Open App: \(appURL)")
print("Status: \(success)")
})
}
}
This worked for me, although the information is just through my own trial and error so it may not be 100% accurate but it works!
Are you using canOpenURL before attempting to actually open the URL? (You ought to in case the second app isn’t installed.) The documentation goes into plenty of detail, about the requirement of including LSApplicationQueriesSchemes in your Info.plist.
You have 2 App to test this issue.
App_B (App open from App_A)
App_A (App start direct open to App_B)
Step : App_B
Choose set schemes Url in App_B (name you want to redirect open for check this App_B is installed)
Ok We set schemes Url complete.
then go to your App_A (your current App)
Step: App_A
1.create your project
2.create func open schemes url
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
openApp_B_installed()
}
func openApp_B_installed(){
//LSApplicationQueriesSchemes in your Info.plist.
let appName = "App_B"
let appScheme = "\(appName)://"
let appUrl = URL(string: appScheme)
if let url = appUrl,
UIApplication.shared.canOpenURL(url) {
print("App installed")
if #available(iOS 10.0, *) {
UIApplication.shared.open(url, options: [:], completionHandler: {
(success) in
if (success)
{
print("OPENED \(url): \(success)")
}
else
{
print("FAILED to open \(url)")
}
})
} else {
// Fallback on earlier versions
UIApplication.shared.openURL(url)
}
}else {
print("App not installed")
}
}
add LSApplicationQueriesSchemes in info plist.
enter image description here
Congratulation you done.
You try to test by install App_A , App_B and install App_A only you can debug in openApp_B_installed()
I hope it helps clarify and resolve the issue for this topic.
Thank you

How to enable "Install" or "Open" Button in facebook messenger in a "yet-to-launch" ios App for Testing

I have an iOS app under development [Not yet launched]
And i want to get the following "Open" button visible on it while sharing the "from my app" via facebook messenger using FBSDKMessengerSharer:
Facebook SDK
What i have done is the following:
As per Facebook's guidelines for Optimized integration.
https://developers.facebook.com/docs/messenger/ios#optimized_integration
I have put .plist entries for facebook app ids, my own app id, URL schemes etc.
i confirm the when i type my scheme://, it open up my app.
Facebook developer console on developer.facebook.com has correct entries for the app/bundle.
I have added myself and another user as test users as per the guidelines and Facebook have clearly written this is testable without submitting the app.
And then i have the following pieces of code for sharing in the app:
func Share(){
let image : UIImage = UIImage(named: "Sample")!
let opts : FBSDKMessengerShareOptions = FBSDKMessengerShareOptions()
opts.contextOverride = cContext
FBSDKMessengerSharer.shareImage(image, withOptions: opts)
}
And the following for enabling optimized sharing in AppDelegate:
func application(app: UIApplication,
openURL url: NSURL,
options: [String : AnyObject]) -> Bool {
print("Called OpenURL")
let h = FBSDKMessengerURLHandler()
let a = "com.appcompany-new.name"
if h.canOpenURL(NSURL(string: "temp://abc.xyz"), sourceApplication: a) {
h.openURL(NSURL(string: "temp://abc.xyz"), sourceApplication: a)
}
return true
}
func messengerURLHandler(messengerURLHandler : FBSDKMessengerURLHandler,didHandleOpenFromComposerWithContext context : FBSDKMessengerURLHandlerOpenFromComposerContext) {
cContext = context
print("Called Open from composer")
}
I donot see any button, the Open, Install or Reply button even now. What am i missing?

Does openParentApplication:reply require App Groups capability to be enabled?

I am developing an app that communicates between the watch and the iOS parent app. It sends data from the WatchKit extension to the parent application by opening it. I understand that openParentApplication:reply, when called, opens the iPhone application from the Apple Watch. After that, application:handleWatchKitExtension:reply is called in the app's delegate.
From there you can open a notification to the view controller with:
NSNotificationCenter.defaultCenter().postNotificationName(aName: String, object anObject: AnyObject?)
"aName" is what you can open up in the view conroller with:
NSNotificationCenter.defaultCenter().addObserver(self,
selector: Selector("handleWatchKitNotification:"),
name: "WatchKitSaysHello",
object: nil)
Here is my code for my interface controller in my WatchKit extension:
//
// InterfaceController.swift
// SendColors WatchKit Extension
//
// Created by Tommy on 12/30/14.
// Copyright (c) 2014 Tommy. All rights reserved.
//
import WatchKit
import Foundation
class InterfaceController: WKInterfaceController {
var ypo = false
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
// Configure interface objects here.
}
#IBOutlet weak var redButton: WKInterfaceButton!
#IBOutlet weak var greenButton: WKInterfaceButton!
#IBOutlet weak var blueButton: WKInterfaceButton!
#IBAction func onRedButtonClick() {
if ypo {
openParentAppWithColor("Yellow")
}
else {
openParentAppWithColor("Red")
}
}
#IBOutlet weak var moreButton: WKInterfaceButton!
#IBAction func moreButtonClick() {
if !ypo {
ypo = true
redButton.setTitle("Yellow")
redButton.setColor(UIColor.yellowColor())
greenButton.setTitle("Purple")
greenButton.setColor(UIColor.purpleColor())
blueButton.setTitle("Orange")
blueButton.setColor(UIColor.orangeColor())
moreButton.setTitle("Back")
}
else {
ypo = false
redButton.setTitle("Red")
redButton.setColor(UIColor.redColor())
greenButton.setTitle("Green")
greenButton.setColor(UIColor.greenColor())
blueButton.setTitle("Blue")
blueButton.setColor(UIColor.blueColor())
moreButton.setTitle("More...")
}
}
#IBAction func onGreenButtonClick() {
if ypo {
openParentAppWithColor("Purple")
}
else {
openParentAppWithColor("Green")
}
}
#IBAction func onBlueButtonClick() {
if ypo {
openParentAppWithColor("Orange")
}
else {
openParentAppWithColor("Blue")
}
}
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
}
override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
}
private func openParentAppWithColor(color: String) {
if ["color": color] != nil {
if !WKInterfaceController.openParentApplication(["color": color], reply: { (reply, error) -> Void in
println(reply)
}) {
println("ERROR")
}
}
}
}
My problem is that say for instance I clicked the red button on the watch simulator. The action would be called and in that action it calls openParentApplicationWithColor("Red") which would call WKInterfaceController.openParentApplication(["color": color], reply: { (reply, error) -> Void in }) What this is supposed to do is open the parent app on the simulator. It opens it in the background. I, therefore open it manually. When I open the app manually, the background is completely black. I suspect the problem is that I did not enable App Groups in the Capabilities tab. In order to do that, you need to be in the developer program. Should I join it to do this, or is there another problem? I am using Xcode 6.2 Beta 3. Thank you all in advance!
I have tested and can confirm that openParentApplication:reply: does not require App Groups to be enabled.
I understand that openParentApplication:reply, when called, opens the iPhone application from the Apple Watch.
This method opens the iPhone app in the background. In previous betas of Xcode 6.2 the app did open in the foreground, but this was not the intended behaviour and is not how the WatchKit Extension-iPhone app communication will work in the shipping version.
You can still launch the iPhone app in the foreground manually, but this isn't necessary unless you want to test the use case of both being used at once. At least with the API currently available, the iPhone app it can't be launched programmatically by the watch app to the foreground, and the watch app can't be launched programmatically by the iPhone app.
Once the app launches, you've reported the screen is still black when you expect it to change colour based on the message you've sent it. Is application:handleWatchKitExtension:reply: being called in the iPhone app? You will know it is definitely being called if you are receiving the reply block back for execution in your WatchKit Extension, which should be outputting something from your println(reply). If so, then the issue is with the code in the iPhone app to do something with the message you've passed to it. It would be useful to see your implementation of that method in your AppDelegate of the iPhone app. (Note if that method failed to call the reply block, it might still be receiving the message and you wouldn't get the reply, but then you would be seeing an error message about the reply not being received.)
Note that you won't see NSLog messages or get breakpoints in Xcode when running the Watch extension initially, but you can select Debug > Attach to process > [select your iPhone app under 'Likely targets'] and then you will get the logs and breakpoints of the iPhone app instead of the Watch app, while still being able to use the Watch app in the watch simulator. Most useful for debugging.
No, you no need to make group enable to use ole parent application. you can make a request to open parent IOS application and waiting a reply from IOS App without setting the group app. You only need to setting the group app when you want to share data between watchkit app and IOS app using NSUserDefauts with suite name.
I am using Xcode 6.2 Beta 5. Select Debug > Attach to process > [select your iPhone app under likely targets is not working. I see the NSLogs for Watch extension but not in iPhone app delegate and view controller of iPhone app.

iOS - Open certain view controller with URL scheme

I'm playing around with URL schemes in my app. I easily made one to open my app, just adding the necessary items to info.plist. This current URL "myappname://" takes the user to the initial view controller, FirstTableViewController, but I was wondering if it would be possible to modify that URL scheme so it I can have one that takes the user to a certain view controller, such as ThirdTableViewController. I would use this as a handy feature in something like Launch Center.
This post is a little old but maybe useful for iOS 5 + because the checked answer is not correct.
AppDelegate doesn't have any navigationController property.
Instead you can do in AppDelegate.m :
enter code here
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
MyViewController *controller = [[MyViewController alloc] initWithNibName:#"MyViewController" bundle:[NSBundle mainBundle]];
UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
[navController presentModalViewController:controller animated:YES];
return YES;
}
Try look at this: Custom Url Schemes
Hope this will be a useful
In ...AppDelegate.m
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
MyViewController *controller = [[MyViewController alloc] initWithNibName:#"MyViewController" bundle:[NSBundle mainBundle]];
[self.viewController presentModalViewController:controller animated:YES];
[controller release];
return YES;
}
Hi here is my solution.
If you can call your navigation function that called in "application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool" event (with a delay) you can navigate a specific page in the app even is not running before called.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Actived keyboard avoider
changeAppereance()
delay(1) {
deeplink = Deeplink()
self.manageNavigation(launchOptions: launchOptions)
self.navigate()
}
return true
}
private func manageNavigation(launchOptions: [UIApplicationLaunchOptionsKey: Any]?) {
if let url = launchOptions?[UIApplicationLaunchOptionsKey.url] as? URL { //Deeplink
print(url.absoluteString)
deeplink = Deeplink()
deeplink?.url = url
}
else if let activityDictionary = launchOptions?[UIApplicationLaunchOptionsKey.userActivityDictionary] as? [AnyHashable: Any] { //Universal link
for key in activityDictionary.keys {
if let userActivity = activityDictionary[key] as? NSUserActivity {
if let url = userActivity.webpageURL {
deeplink = Deeplink()
deeplink?.url = url
}
}
}
}
}
open func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
print(url.absoluteString)
deeplink = Deeplink()
deeplink?.url = url
navigate()
return true
}
Posting a new answer for Swift 5. Many of the answers are outdated or address handling custom URLs, but not specifically how to open a UIViewController from within the AppDelegate. Run this code within your AppDelegate:
//Get the view controller that is currently displayed upon launch
let rootViewController = window?.rootViewController
//Initialise the view controller you wish to open
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "MyViewController")
//Launch the view controller
rootViewController.present(vc, animated: true)
Yes it is possible to modify URL scheme so that you can jump user to any viewcontroller.I used and implement normal as well as https://hokolinks.com/ deep link.By hoko link deep linking you can modify your URL Scheme ,also you can send data with that URL.
Integrate iOS SDK Using Hoko Link
- Add a URL Scheme to your App
- SDK Setup
To integrate HOKO open source SDK in your app (only iOS 5 and higher) you just have to follow 3 simple steps (either using cocoapods or doing it manually).
Using CocoaPods
1- Install CocoaPods in your system
2- Open your Xcode project folder and create a file called Podfile with the following content:
pod 'Hoko', '~> 2.3.0'
3- Run pod install and wait for CocoaPods to install HOKO SDK. From this moment on, instead of using .xcodeproj file, you should start using .xcworkspace.
Manual integration
1- Download the Hoko SDK.
2- Drag the Hoko folder to your project.
3- Be sure to also add SystemConfiguration.framework and zlib.dylib in case your project does not include it already.
Integrating the SDK with your Swift project
Because the HOKO SDK is written in Objective-C, you’ll have to manually add a Bridging Header file into your project in order to use it with your Swift code:
1- File > New > File... > iOS > Source > Header File
2- Name that header file YourAppName-Bridging-Header.h
3- Inside that header file, import #import
4- Go to your project > Build Settings > Search for Objective-C Bridging Header > Add the path to your bridging header file, from your root folder (e.g. MyApp/MyApp-Bridging-Header.h)
Add a URL Scheme to your App
Next, we need to define your app’s custom URL type, if you don’t have one already. Open your Xcode project settings and under the “Info” tab expand the “URL Types” section. You can skip this step if you already configured a URL type.
If this section is empty, click in the “+” icon to add a new URL type. Let’s say that we want to open the app via “hoko://”. Hence we need to enter “hoko” in URL Schemes.
We also should assign a unique Identifier to this URL type. Apple recommends that you use reverse DNS notation to ensure that there are no name collisions between types. In this example we are going to use “com.hoko.app”.
Take note of your URL Scheme because we will ask you for it, when you are creating an app through the dashboard, e.g. “hoko”.
URL Scheme
Setup Associated Domains (Universal Links) - iOS 9.0+
For your app to fully support the newly introduced Universal Links by Apple you’ll have to enable and add a new entry in the Associated Domains section, inside your application target’s Capabilities tab. Click on the ‘+’ button and add a new entry with the following value: applinks:myapp.hoko.link, being myapp the Hoko subdomain you chose for your app’s Hoko links. You can also have your own link domain (learn more about this on the subdomains section).
URL Scheme
SDK Setup
Add the following line to your applicationDidFinishLaunching method in your AppDelegate class (don’t forget to import the HOKO class by using #import if you’re working with Objective-C).
Objective-C
Swift
#import
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[Hoko setupWithToken:#"YOUR-APP-TOKEN"];
// The rest of your code goes here...
return YES;
}
If you are using a custom domain in your smart links, you must setup the iOS SDK using setupWithToken:customDomain: as following:
Objective-C
Swift
#import
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[Hoko setupWithToken:#"YOUR-APP-TOKEN"
customDomain:#"your.custom.domain.com"];
// The rest of your code goes here...
return YES;
}
NOTE: make sure to return YES in the application:didFinishLaunchingWithOptions: delegate method to allow incoming deep links that open your app to be processed. Returning NO will block the requests.
Setup your mobile deep linking by using Hoko Link SDK

Resources