How to open app from other app within app in iOS - move

How to move from one app to another app in iOS.
How to go from one to another app if app exist in device at that moment.

let url = NSURL(string: "NameOfTheAppAsOnAppStrore:")
// canOpenURL will return a bool value checking the presence of app in your device and if app is present, it will open the same.
if UIApplication.sharedApplication().canOpenURL(url!)
UIApplication.sharedApplication().openURL(url!)
}

Related

SwiftUI macOS app with `App` protocol deep linking opens new app instance

This is in a SwiftUI macOS app using the new App protocol and #main.
Usage flow:
User launches app and clicks a button which opens a particular webpage
Webpage eventually redirects to the app's URL scheme, opening the app and invoking onOpenURL(_:)
Expected behaviour:
The deep link is sent to the existing, currently open app instance
Actual behaviour:
A new app instance is launched, causing two instances of the app to be active
Note: There isn't really any code to add since the problem is just dependent on adding a URL scheme to the app and having a webpage go to it.
onOpenURL(_:) is not actually launching a new app instance, it is creating a new window within the existing instance. The documentation would suggest this only happens on macOS (because iOS only supports a single window).
You need to use the .handlesExternalEvents(preferring:allowing:) modifier on a higher order view. Calling handlesExternalEvents will override the default behaviour which is what is creating the new window in your app on macOS. Something like:
#main
struct myApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.handlesExternalEvents(preferring: ["myscheme"], allowing: ["myscheme"])
}
}
}
An then in a child view (e.g. ContentView()):
var body: some View {
VStack {
// your UI
}
.onOpenUrl{ url in
// do something with the deep link url
}
}

macOS - Impossible to launch an app with localized name and space

I have this macOS app that is launched at login. This app has a space in the name "My App.app".
For that matter, I have created a helper app that loads at login and launches the main app.
I am inside this helper, trying to launch the main app.
For this reason I need to get the main app path. So, I do:
let appName = "My App.app"
let path = "/Applications/" + appName
let newURL = NSURL.fileURL(withPath: path)
when I try to use this
let app = try NSWorkspace.shared.launchApplication(at: newURL,
options:[.withErrorPresentation, .inhibitingBackgroundOnly, .async],
configuration: [:])
I get an error "APPLICATION NOT FOUND".
One of the problems is that the App contains a space in the name "My App.app". I remove the space in the app name and this command successfully launches the app.
But I need the space in the name.
Then I try to launch the app using the bundle identifier.
NSWorkspace.shared.launchApplication(withBundleIdentifier: mainAppBundleIdentifier,
options: [.withErrorPresentation, .inhibitingBackgroundOnly, .async],
additionalEventParamDescriptor: nil,
launchIdentifier: nil)
then I get another error,
MyApp can’t be opened. Move “My App” to the Applications folder and try again.
The problem is that the app is already on the Applications folder.
then I use this, just to check
let path = NSWorkspace.shared.absolutePathForApplication(withBundleIdentifier: mainBundleId)
and I get this
"/Users/myself/Library/Mail/V6/0982138471-EA33/[Gmail].mbox/All
Mail.mbox/871628745618726547816A/Data/2/8/5/Attachments/582584/2/MyAppMac.app"
WTF!!??
Two things wrong about this:
This is a link to an email I have sent yesterday to a tester, sending him the application.
The app mentioned in the link is MyAppMac.app that is the Xcode target name, without localization.
How in the heavens name do I launch an app from another app when the app contains a space in the name and is localized?
How do I get the target name?
The usual way to launch the main application is first to check if it's already running and if not to run the executable and pass a variable to inform the main application that it was launched by the helper
For example
func applicationDidFinishLaunching(_ aNotification: Notification) {
let appName = "Foo"
let bundleIdentifier = "com.spacedog.foo"
if NSRunningApplication.runningApplications(withBundleIdentifier: bundleIdentifier).isEmpty {
let bundleURL = Bundle.main.bundleURL
var pathComponents = bundleURL.pathComponents
pathComponents.removeLast(3)
pathComponents.append(contentsOf: ["MacOS", appName])
let mainAppURL = NSURL.fileURL(withPathComponents:pathComponents)!
let options = [NSWorkspace.LaunchConfigurationKey.arguments : ["launchedAtLogin"]]
_ = try? NSWorkspace.shared.launchApplication(at: mainAppURL as URL, options: .withoutActivation, configuration: options)
}
NSApp.terminate(nil)
}

Open Native iOS app from Xamarin.Forms

I have an native iOS sample app installed in my iPad and also my sample xamarin.Forms App installed. I want to open native iOS app from Xamarin.forms when clicked on button. I have set URL schema in my native iOS app in info.plist.
How do I open native app from xamarin.forms on click of a button. I already tried
var request = Device.OnPlatform(
string.Format("native app url"),
string.Format("native app url"),
string.Format("native app url"));
Device.OpenUri(new Uri(request));
but its not working.
It's basically how you are doing it.
var url = Device.OnPlatform(iOSUrl, androidUrl, winPhoneUrl);
Device.OpenUri(new Uri(request));
Be aware that each platform have some requirements in the way to url is configured and parameters are sent.
Let say to get the maps app open in each platform you would use these urls schemes:
// iOS doesn't like %s or spaces in their URLs, so manually replace spaces with +s
var iOSUrl = string.Format("http://maps.apple.com/maps?q={0}&sll={1}", name.Replace(' ', '+'), loc);
var androidUrl = string.Format("geo:0,0?q={0}({1})", string.IsNullOrWhiteSpace(addr) ? loc : addr, name);
var winPhoneUrl = $"bingmaps:?cp={loc}&q={name}";
var url = Device.OnPlatform(iOSUrl, androidUrl, winPhoneUrl);
Also you cannot open any arbitrary app unless you know its Url scheme.
Anyway, if the Device.OpenUri() doesn't fulfill your requirements you are good to create your own implementations using the native APIs.
Please go through the below link and attached photo
Link:-launch-an-app-from-within-another-iphone
I am using below code in xamarin forms
NSUrl request = new NSUrl("Camera://");
var canOpen = UIApplication.SharedApplication.CanOpenUrl(new NSUrl(request.ToString()));
if (!canOpen)
{ Task.FromResult(false); }
else
{
Task.FromResult(UIApplication.SharedApplication.OpenUrl(new NSUrl(request.ToString())));
}

Unable to make my OS X app (written in swift) launch at login

Some details:
I am not enrolled into Mac Developer program, hence the code is not signed.
I am not sandboxing the app.
It's a status bar only app, no dock or menu will appear.
Here's what I did:
Added a new project for helper app on top my existing main app project.
In main app settings:
Added ServiceManagement.framework framework to my main app.
Set Strip Debug Symbols During Copy to NO
In Build Phases tab, under Copy Files, added Contents/Library/LoginItems as Subpath. And added my Helper App.app
For helper app settings:
Set Application is background only to YES
Under Build Settings, set Skip Install to YES
Hocus Pocus.app is my main app and Hocus Pocus Helper.app is helper app.
In AppDelegate of helper app, my code is:
func applicationDidFinishLaunching(aNotification: NSNotification) {
NSWorkspace.sharedWorkspace().launchApplication("Hocus Pocus.app")
NSApplication.sharedApplication().terminate(self)
}
In AppDelegate of main app:
...
override init() {
self.mainBundle = NSBundle.mainBundle()
let path = mainBundle.bundlePath.stringByAppendingPathComponent(
"Contents/Library/LoginItems/Hocus Pocus Helper.app")
self.helperBundle = NSBundle(path: path)!
super.init()
}
...
...
func makeThisAppStartAtLogin(state: Int) {
let result = SMLoginItemSetEnabled(helperBundle.bundleIdentifier!, Boolean(state))
if result != 0 {
println("success")
}
else {
println("failed")
}
}
It's not working when I call makeThisAppStartAtLogin(1), why?
Apple documentation mentions:
The Boolean enabled state of the helper application. This value is effective only for the currently logged in user. If true, the helper application will be started immediately (and upon subsequent logins) and kept running. If false, the helper application will no longer be kept running.
When I call makeThisAppStartAtLogin(_:), it should start helper app immediately. But it doesn't seem to be doing that.
The if block prints success.
In Helper App code, I also sent the path to launchApplication(_:) instead of app name, it did not make any difference.
I have ran this app from default debug directory and also under /Applications
I have also tried following, it didn't make any difference:
...
let launchDaemon: CFStringRef = "avi.Hocus-Pocus-Helper"
if SMLoginItemSetEnabled(launchDaemon, Boolean(state)) {
...
I have checked that helper app is copied to main app at correct path.
When I launch the helper app manually, either from debug folder or from main app's Contents, it does launches main app and kill itself, as it should.
Here's the full repository, if you are interested. Check loginitems branch.

iOS8 app crashes on Xcode6.0.1 using HealthKit

Im actually trying to convert Apple's sample code to swift.
I created an app and an APPID for it in the devcenter. I checked the entitlement for HealthKit (the ones for IAP & GC are greyed and checked automatically).
When the provisioning profile I create for it is downloaded to Xcode and I go into Preferences in Xcode and look at my account's provisioning profiles I can see the name of the profile plus the expiration date and then there are some icons for entitlements. But the provisioning profile I created with HealthKit doesnt have any icon for it, just the 2 default ones, is this normal:
because for some reason the app crashes upon requesting authorization with this error:
2014-10-02 12:16:13.241 SwimFit[549:8824] -[__NSCFConstantString _allowAuthorizationForSharingWithEntitlements:]: unrecognized selector sent to instance 0x107dc1ce0
2014-10-02 12:16:13.251 SwimFit[549:8824] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFConstantString _allowAuthorizationForSharingWithEntitlements:]: unrecognized selector sent to instance 0x107dc1ce0'
If I try to run it on the device I get this:
I have created:
AppId for my app
Activated that AppID for HealthKit
Created Dev provisioning profile for that AppID
Activated HealthKit Capabilities in General
I see the entitlements.plist is created with com.apple.developer.healthkit = yes
The info.plist does have the healthkit value for required capabilities
The only weird thing I did this time and I used to do differently for other apps is that when I clicked on build/run a some point, I let Xcode create an AppID and I get this from devcenter...i cant upload the image but basically all my previous AppIDs are named after the app. This one because its made by xcode is named: Xcode iOS App ID com santiapps SwimFit but its bundle identifier is correct at: com.santiapps.SwimFit. And so is the dev profile: iOS Team Provisioning Profile: com.santiapps.SwimFit and its the one in my Build Settings. Originally I had SwimFit because that was the name of the app so Xcode created an automatic AppID for it with a ProvProfile for it as well. I then thought maybe I should create the appID and provprofile so I did it manually and tried calling it SwimFit2. Both give the same error.
What else could I be missing?
Here is the code:
//1. Add healthstore property
var healthStore: HKHealthStore? //error if not optionally unwrapped
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
//2. Ask for permissions
if (HKHealthStore.isHealthDataAvailable() == true) {
self.healthStore = HKHealthStore() //needs to be var for it to work?
var writeDataTypes = self.dataTypesToWrite()
var readDataTypes = self.dataTypesToRead()
self.healthStore!.requestAuthorizationToShareTypes(writeDataTypes, readTypes: readDataTypes, completion: { (success: Bool, error: NSError!) -> Void in
if (!success) {
NSLog("You didn't allow HealthKit to access these read/write data types. In your app, try to handle this error gracefully when a user decides not to provide access. The error was: %#. If you're using a simulator, try it on a device.", error)
return
} else {
NSLog("success")
}
// Handle success in your app here.
self.setupHealthStoreForTabBarControllers()
})
}
return true
}
Here is a link with a screen capture: http://youtu.be/BBagkNTpfQA
I had the same crash yesterday. The problem is that you put the wrong data type (NSString) for the data types into the method.
The requestAuthorizationToShareTypes method requires you to pass a set of HKBaseType objects, in my case HKQuantityType objects.
So instead of:
[_healthStore requestAuthorizationToShareTypes:[NSSet setWithObject:HKQuantityTypeIdentifierBodyMassIndex]
readTypes:[NSSet setWithArray:inputDataTypes]
completion:
Use this one:
HKQuantityType* type = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMassIndex];
[_healthStore requestAuthorizationToShareTypes:[NSSet setWithObject:type]
readTypes:[NSSet setWithArray:inputDataTypes]
completion:

Resources