I create project for os x application with xpcservices that run by loginItems. that's mean the service is founded in the app in the path:{APP_NAME}.app/Contents/Library/LoginItems
and who is responsible for run the service is the the main app:
NSXPCConnection *connection = [[NSXPCConnection alloc] initWithLoginItemName:#"{SERVICE_NAME}.app" error:&error];
I used the class :NSXPCConnection+LoginItem.h from apple's docs example :
https://developer.apple.com/library/mac/samplecode/AppSandboxLoginItemXPCDemo/Listings/iDecide_NSXPCConnection_LoginItem_h.html
Q:
Why when I update the service code (even just logs) it's not changed?
you should know:
I deleted all the files that related to this projects and service
( I don't used LaunchAgents or LaunchDaemons folders)
I did remove the service by: launchctl remove {SERVICE_LABLE}
I used the Console App for seeing the difference between the version that I'm running
I even bought "cleanMyMac3.app" and did restart and still I run from Xcode the app and still show logs from previous version.
I searched file on the system that related to the service name, and I find few folders that created and I deleted them:
~/Library/Group Containers/{SERVICE_NAME}
~/Library/Containers/{SERVICE_NAME}
~/Library/Caches/{SERVICE_NAME}
~/Library/Saved Application State/{SERVICE_NAME}
I'm not work sandbox
Do you reference the service (XPC service) properly?
i.e. (as per Apples Example)
`NSXPCConnection *connection = [[NSXPCConnection alloc] initWithLoginItemName:#"XYZABC1234.com.example.iDecideHelper.app" error:&error];`
Also as this example is pretty old, if you traverse the XPC requirements you'll notice that some changes need to be made:
Both the containing project (the iOS or OSX App) and the XPC service App ned to be sandboxed
Ideally, the XPC service should be named as: com.theMainApp.identifier.com.whateverServiceName.
So in the Apple example you've listed IDecideHelpers identifier would be: com.example.iDecide.WhateverServiceName. iDecide (the main app) would be com.example.iDecide
Related
I'm trying to upload data using NSURLSession with a background task from an OSX share extension.
As soon as I start the task, by delegate is called back with the world's least helpful error message:
The operation couldn’t be completed. (NSURLErrorDomain error -995.)
There's no other information in the NSError object, nor in the console.
After scouring the internet, the only clue I have is to make sure that I've set up the configuration.sharedContainerIdentifier correctly, however I've already done that:
let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(uniqueId)
configuration.sharedContainerIdentifier = Config.appGroupName
urlSession = NSURLSession.init(configuration: configuration, delegate: self, delegateQueue: nil)
I then prepare the request and create the task:
let task = self.urlSession!.dataTaskWithRequest(request)
self.tasks.append(task)
task.resume()
Note that everything works perfectly when from my main app. It's just the sharing extension that fails.
What other problems could cause error -995?
(Bear with me, I don't have rep yet for a comment so I have to answer, and notwithstanding the possibility you've found a bug, the last part I'm adding might help others)
When you're using an NSURLSession any background upload/download that completes will launch your main application. This is detailed in the Common Scenarios page.
As you show you've done, you need to set the NSURLSessionConfiguration with a sharedContainerIdentifier:
let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(uniqueId)
configuration.sharedContainerIdentifier = Config.appGroupName
urlSession = NSURLSession.init(configuration: configuration, delegate: self, delegateQueue: nil)
You also need to ensure that both your app extension and your main app are all triple-checked in the 'App Groups' option in Xcode (I'm looking at Xcode 8.1), which means:
The app group name is the same for both app and extension(!)
the check beside Add the App Group entitlements in the entitlement file
the check beside Add the App Groups feature to your App ID
the check beside Add App Groups to your App ID
And the checks need to be there on both app and extension.
I'm a bit rusty on adding these but my recollection is these aren't listed in the right order, e.g. you have to 'Add App Groups to your ID' before you can check them in both app and extension, but I could be wrong.
Advanced - Thirdparty libraries in app extensions.
Looking at the github project nst/STTwitter, a third-party Twitter REST library, they needed to add a configurable group ID to allow setting the NSURLSessionConfiguration sharedContainerIdentifier to the library user's group ID.
I may again be mistaken but this seems like it would be a general problem when using thirdparty libraries in an app extension - e.g. I've just now come across this error when trying to use the ChromeCast SDK and this could be the kick in the pants.
I'm trying to experiment with web view by using swift. I created a simple Xcode project, placed a web view within my application interface and connected it to my app delegate.swift with an outlet called "myview". By executing
self.myview.mainFrameURL = "http://www.google.com"
from within applicationDidFinishLaunching(), I would expect the Google's homePage to be loaded. However, this doesn't happen: the web view does not show anything. What am I doing wrong?
1) Add the NSAppTransportSecurity in your plist https://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/
2) check in your project settings that "Sandbox" is enabled and that internet connections are allowed
You will have to call loadRequest() to make it load a page.
So basically:
[self.myWebView loadRequest: [NSURLRequest requestWithURL:
[NSURL URLWithString: #"http://www.google.com"]]]
After digging into the console logs, I found the solution to my problem. I'm not sure if I can share it though, since I'm using a beta OS X version and this restriction could have been introduced to improve apps' security, even if from what I can see it can be disabled.
I'm attempting to add functionality to an application that is similar in function to the "Open With..." menu in the Finder. In the application I'm working on, a user can select a file and chose to open it with a specific application, rather than with the default one.
The problem I'm experiencing is that there appears to be a mis-match in the APIs I think I should be using in order for this to work properly. Specifically, the recommended NSWorkspace API for opening files with a specific application takes a bundle identifier to specifying the application:
[NSWorkspace openURLs:
withAppBundleIdentifier:
options:
additionalEventParamDescriptor:
launchIdentifiers:]
However, the Launch Services API for getting a list of applications that can open a given file returns an array of URLs, each pointing to a compatible application:
CFArrayRef LSCopyApplicationURLsForURL(CFURLRef inURL, LSRolesMask inRoleMask);
Currently, I'm iterating over the array that launch services returns and extracting the bundle identifier by creating a new NSBundle each time:
for (NSURL *applicationURL in applicationURLs) {
NSBundle *applicationBundle = [NSBundle bundleWithURL:applicationURL];
NSString *bundleIdentifier = applicationBundle.bundleIdentifier;
// Do something with bundle identifier...
}
The problem I'm experiencing is that if the applicationURL points to an application that is not under /Applications (or any other directory my sandboxed application has read access to), then I cannot create an NSBundle to read the bundle identifier. Instead, Gate Keeper will output a sandbox violation to Console.app and NSBundle bundleWithURL will return nil.
Is there a way I've overlooked to get the bundle identifier from a URL that I've overlooked? Or is there a different way to read the bundle identifier from an arbitrary file without causing a sandbox violation? Or maybe there's a different way to get a list of all applications that can open a specific URL?
(Note that the Launch Services method to open multiple URLs, LSOpenURLsWithRole has been deprecated. The header file simply says "Use NSWorkspace".)
I need to open a NSSavePanel with the users Library folder as destination folder. Normally I would do this by entering ~/Library/ in [NSSavePanel beginSheetForDirectory].
This works fine as long as the application is not sandboxed. For sandboxed applications this will result in the NSSavePanel trying to access a folder inside the applications document "box".
I cannot refer to /Users/username/Library/ as I do not know the users username at runtime. So how do I link to this path in cocoa?
I'm not sure how sandboxing fits in with this, but you can find the user's library directory using:
NSArray* paths = NSSearchPathForDirectoriesInDomains( NSLibraryDirectory, NSUserDomainMask, YES );
Not sure if this will work on a sandboxed application but this is how I do it right now. This will return /User/TheirUserName
-(NSString *)homeDirectory
{
return NSHomeDirectory();
}
It depends what you are trying to achieve.
If the behavior is required by your application, then you can request a temporary exception entitlement when submitting the application to the Mac App Store. But sooner or later, you will have to find a solution to remove this exception.
If you want to access data that were previously stored in the ~/Library/ folder, you can define a migration strategy to move back the data into the sandbox.
First of all I would like to thank all of the contributors of this site.
Now for the questions:
I have implemented a simple system service using the System Services Guide and posts on this site.
I would like to find out the name of the application that initiated the call to my service either in my - (void)handleServices:(NSPasteboard *)pboard or via some other means.
The application that initiated the call to your service has to be the most active.
So you can get information about it via NSWorkSpace:
[[[NSWorkspace sharedWorkspace] activeApplication] valueForKey:#"NSApplicationName"] // you might also be interested via #"NSApplicationBundleIdentifier
I just tested this with a very basic Service, and it works as expected.