1

I am trying to check if a user has installed a couple of apps. I need it to work on ios9 and ios 10. I am testing on ios9 first and the schemeAvailable func is returning true even though the app passed is not installed on the device.

func schemeAvailable(scheme: String) -> Bool {
   if let url = URL(string: scheme) {
       return UIApplication.shared.canOpenURL(url)
   }
   return false
}

I have added the following to my info.plist i.e. the apps I will check are installed:

<key>LSApplicationQueriesSchemes</key>
<array>
<string>app1</string>
<string>app2</string>
</array>

and in my project's info tab, I have added 2 url types and inserted the identifier and url scheme for each.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
user2363025
  • 6,365
  • 19
  • 48
  • 89
  • Possible duplicate of [openURL: deprecated in iOS 10](http://stackoverflow.com/questions/39548010/openurl-deprecated-in-ios-10) – dmorrow Mar 07 '17 at 15:32
  • @dmorrow i'm explaining an issue with ios9 – user2363025 Mar 07 '17 at 15:34
  • `canOpenURL` isn't deprecated – dan Mar 07 '17 at 15:46
  • Can you share the actual url schemes - not `app1` and `app2`? – dmorrow Mar 07 '17 at 15:48
  • @dmorrow com.companyname.app1, com.companyname.app2. They aren't published in the store yet. They are local apps – user2363025 Mar 07 '17 at 15:50
  • @dan apologies, my mistake!! – user2363025 Mar 07 '17 at 15:52
  • Can you debug the `schemeAvailable` method call and confirm what value you are passing for `scheme`? – dmorrow Mar 07 '17 at 16:24
  • @dmorrow should scheme be my app's display name or bundle identifier? followed by :// ? Also my apps are part of an appgroup. Is there any chance this has something to do with my issue? – user2363025 Mar 07 '17 at 16:26
  • @dmorrow If I run the test passing in "fb://", it reports correctly for installed or not but not my own apps. I'm not sure what the protocol is for my app i.e. if it should be displayname or bundle identifier and if that needs to be prepended with my app group container's identifier – user2363025 Mar 07 '17 at 16:45
  • @user2363025 - have you set up your app1 and app2 to use a custom URL scheme? – DonMag Mar 07 '17 at 19:43
  • Be sure to add `CFBundleURLTypes` to app1/info.plist with `app1`. – dmorrow Mar 07 '17 at 20:51
  • @dmorrow When I add this, then schemeAvailable returns true for both even tough 1 is uninstalled – user2363025 Mar 08 '17 at 09:16
  • @Donmag if you mean added the url types to my plist, then yes – user2363025 Mar 08 '17 at 09:17
  • To clarify, which info.plist did you add it to? We are talking about 3 apps here - app1.app, app2.app and this unnamed app you are checking from. – dmorrow Mar 08 '17 at 13:01
  • @user2363025 - sounds like a little confusion on what needs to be where. I posted an answer with graphics that should help you figure it out. – DonMag Mar 08 '17 at 13:47
  • @dmorrow in app 3, I had added the CFBundleURLTypes for app1 and app2. I see now via the answer below where I had went wrong, thanks! – user2363025 Mar 08 '17 at 14:04

2 Answers2

3

It sounds like you do NOT have all registrations correct. Your App1 and App2 each need URL Identifiers and Schemes, and your app that "wants to launch App1 and App2" must have LSApplicationQueriesSchemes defined.

E.G.

This is in "App1"

enter image description here

This is in "App2"

enter image description here

This is in "LauncherApp"

enter image description here

Then, in "LauncherApp" I can do:

    let s = "DMCApp1://TestMe"
    let customURL: URL = URL(string: s)!

    if UIApplication.shared.canOpenURL(customURL) {
        print("YES - I can open App1 !!!")
        UIApplication.shared.open(customURL, options: [:], completionHandler: nil)
    } else {
        print("NO - App1 is not available.")
    }
DonMag
  • 69,424
  • 5
  • 50
  • 86
0

You don't have to add the other apps' schemes on your app plist. If you do that you app becomes the responder to URL with that scheme and always be true.

canOpenURL method is not marked as deprecated on documentation

I copy a snippet with part of the code I use to open app url by custom schemes...

/**
    Abre los perfiles de la app en las distintas redes sociales.

    - Parameters:
        - url: Esquema personalizado de la app
        - secondaryURL: Si la app no está presente en el dispositivo abrimos su version web (twitter, facebook, etc...)
*/    
    func open(_ url: String, secondaryURL: String? = nil) -> Void
        {
            if let url = URL(string: url), UIApplication.shared.canOpenURL(url)
            {
                UIApplication.shared.open(url, completionHandler: nil)
            }
            else if let secondaryURL = secondaryURL, let url = URL(string: secondaryURL), UIApplication.shared.canOpenURL(url)
            {
                UIApplication.shared.open(url, completionHandler: nil)
            }
            else 
            {
                print("No se puede hacer nada de nada.\r\napp_url: \(url)")
            }
        } 

And here's an example. I try to open twitter app, and if not presented, open Safari and shows the twitter web page.

@IBAction private func handleTwitterButtonTap(sender: UIButton) -> Void
{
    let twitter_app_url: String = "twitter://user?screen_name=GetPomodoroApp"
    let twitter_web_url: String = "https://twitter.com/GetPomodoroApp"

    self.open(twitter_app_url, secondaryURL: twitter_web_url)
}
Adolfo
  • 1,862
  • 13
  • 19
  • if I remove the 2 url types, identifier and url scheme in my project's info tab, then I get failed for URL: "app1://" - error: "(null)" AND failed for URL: "app2://" - error: "(null)" even though app2 is installed – user2363025 Mar 07 '17 at 15:39
  • Hi @user2363025. I've add an example. – Adolfo Mar 07 '17 at 15:43
  • This answer is confusing. The schemes must be listed under `LSApplicationQueriesSchemes`. – rmaddy Mar 07 '17 at 15:45
  • Schemes must be listed for your own app (your own scheme). But no register external schemes, like twitter, facebook... @rmaddy – Adolfo Mar 07 '17 at 15:47
  • @Adolfo That's incorrect. Any URL scheme you use with `canOpenURL` must be listed under `LSApplicationQueriesSchemes`. This has been a requirement since iOS 9. – rmaddy Mar 07 '17 at 15:48
  • Try with instagram (for example). let instagram_app_url: String = "instagram://user?username="..." ;) @rmaddy – Adolfo Mar 07 '17 at 16:00
  • Hi @rmaddy You're right, with canOpenURL you need to register the scheme. I *change* the conversation in my mind to `openURL` ;) – Adolfo Mar 07 '17 at 16:12