Is it possible to use Scripting Bridge to open an app, but move it to the background? - objective-c

I'm trying to open the app Spotify, and move it to the background. I can easily open Spotify with
SpotifyApplication *Spotify = [SBApplication applicationWithBundleIdentifier:#"com.spotify.client"];
[Spotify activate];
But Spotify goes to the foreground, covering my windows. With iTunes, I can use
iTunesApplication *iTunes = [SBApplication applicationWithBundleIdentifier:#"com.apple.iTunes"];
[iTunes run];
However it's an iTunes specific method. Is this possible?

Would you be willing to use NSAppleScript to do it?
NSAppleScript *script = [[NSAppleScript alloc]
initWithSource:#"tell app \"Spotify\" to launch"];
NSDictionary *errorInfo;
[script executeAndReturnError:&errorInfo];
if (errorInfo) {
NSLog(#"error: %#", errorInfo);
}
You have to use the application name, not its bundle ID.

Related

How to resume multiple background downloads using AFURLSessionManager in iOS app

I have an iOS app that provides multiple book download at the same time, Its a reader app actually. Earlier I was using AFDownloadRequestOperation for download the book. When user launch the app after app crashes or after user force quit (kill) the app, It automatically resume the download from the offset where it left downloading and for this to achieve I was using the following method:
AFDownloadRequestOperation* operation = [[AFDownloadRequestOperation
alloc] initWithRequest:request targetPath:path shouldResume:YES];
Now I am using AFNetworking 2.0 API AFHTTPSessionManager for background download. I have created the background session in the following way:
NSString* strIdentifier = [NSString stringWithFormat:#"someUniqueIdentifier"];
NSURLSessionConfiguration *sessionConfig;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >=8.0f)
{
sessionConfig =[NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:strIdentifier];
}
else
{
sessionConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:strIdentifier];
}
self.backgroundSessionManager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:sessionConfig];
Then I have started the background download task as follows with delegate callbacks:
self.bookDownloadTask = [self.backgroundSessionManager downloadTaskWithRequest:request progress:nil destination:nil completionHandler:nil];
[self.bookDownloadTask resume];
So again considering the earlier situation -
When user launch the app after app crashes or after user force quit (kill) the app, It does automatically start (not resume) the download but not from the offset where it left downloading, it start downloading form starting of the book.
Is there any way to automatically resume the download from the offset where it left downloading using AFHTTPSessionManager ??
Any help would be appreciated. Thanks !!

Setting Mac OSX 10.11 Volume Programatically using XCode

I need a way to change volume (and mute the volume) in osx 10.11
There was a way before 10.11 and that code was
AudioObjectPropertyAddress propertyAddress = {
kAudioHardwareServiceDeviceProperty_VirtualMasterVolume,
kAudioDevicePropertyScopeOutput,
kAudioObjectPropertyElementMaster
};
AudioHardwareServiceSetPropertyData([self.class defaultOutputDeviceID],
&propertyAddress,
0,
NULL,
sizeof(Float32),
&volume);
But this no longer works in 10.11
The other way I found was using applescript
NSAppleScript* asdown = [[NSAppleScript alloc] initWithSource:#"output volume of (get volume settings)"];
NSAppleEventDescriptor *result = [asdown executeAndReturnError:nil];
NSAppleScript* asdown2 = [[NSAppleScript alloc] initWithSource:[NSString stringWithFormat: #"set volume output volume (%# - 6.25)", [result stringValue]]];
NSAppleEventDescriptor *result2 = [asdown2 executeAndReturnError:nil];
But I dont like to use this way because when the screen it turned off, about 30 seconds after it no longer responds to commands
So is there a way for me to be able to change the volume of the mac running 10.11 without using applescript?

How to launch Apps, from my App, with a custom parameter so I can check whether the app was launched by me?

I'm working on this app that launches other apps. I'm listening to app launches using:
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
selector:#selector(appLaunched:) name:NSWorkspaceDidLaunchApplicationNotification
object:nil];
And I launch them using (Mail is just an example):
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSArray arrayWithObject:#"lalalala"], NSWorkspaceLaunchConfigurationArguments, nil];
[[NSWorkspace sharedWorkspace] launchApplicationAtURL:[NSURL URLWithString:#"/Applications/Mail.app"] options:NSWorkspaceLaunchWithoutActivation configuration:dict error:nil];
I did some research, and I saw that you can send an argument when you launch an app (that's why I used the var dict in the code above), but I'm having an issue with this: even using NSWorkspaceLaunchWithoutActivation, the Mail.app is launched and becomes focused with a new composing window. I don't know why it's doing that.
Another thing, if I manage to successfully send a custom argument without focusing the app, how can I check if the app was launched by me (check if the argument is there)?
PS: I'm looking for App Store-ready methods.
Send the timestamp (UTC) together with the app name you started to your server or a local file if possible.
Then you can track it.
Firstly, I'd try NSWorkspaceLaunchAndHide if NSWorkspaceLaunchWithoutActivation isn't "working". Not ideal, no.. but a kludge...
Secondly... here's a "full, running example" that does the trick..
#import <Cocoa/Cocoa.h>
NSString *psAUX(NSString*grep) {
FILE *read_f; char buff[BUFSIZ+1]; int char_rd; NSString *res, *cmnd;
memset(buff, '\0', sizeof(buff));
cmnd = [NSString stringWithFormat:#"/bin/ps aux|grep -i %#",grep];
read_f = popen(cmnd.UTF8String, "r");
if (read_f == NULL) return nil;
char_rd = fread(buff, sizeof(char), BUFSIZ, read_f);
if (!char_rd) return nil;
return res = [NSString stringWithUTF8String:buff], pclose(read_f), res;
}
int main(int argc, char *argv[]) { #autoreleasepool {
NSString* secretStr; NSURL *mailURL; NSDictionary *cfg; NSWorkspace *ws; NSApplication.sharedApplication;
secretStr = #"TAMPAX";
mailURL = [NSURL URLWithString:#"file:///Applications/Mail.app"];
cfg = #{NSWorkspaceLaunchConfigurationArguments:#[secretStr]};
ws = NSWorkspace.sharedWorkspace;
[ws launchApplicationAtURL:mailURL options:0 configuration:cfg error:nil];
fprintf(stderr,"%s",
[psAUX(#"Mail.app") containsString:secretStr]
? "You ARE Mail's baby's daddy!"
: "Hands off, she's NOT yours!");
[NSApp run]; } }
NSLog -> You ARE Mail's baby's daddy!
Congratulations!
You can create a new Task using NSTask. With NSTask you can set arguments as well as some environment variables to app so that you can check if it is launched by you or by someone else.
Here is the sample code sniffet to do so:
NSTask* taskApp = [[NSTask alloc] init];
[taskApp setLaunchPath:#"App path goes here"];
[taskApp setArguments:[NSArray arrayWithObjects:#"Arg1",#"arg2", nil]];
[taskApp setEnvironment: [[NSProcessInfo processInfo] environment]];
[taskApp launch];

Window Constantly Wants To Be On Top Of Others - Xcode

My app has buttons that open automator workflows like this:
- (IBAction)actionname:(id)sender {
NSTaskname = [[NSTask alloc] init];
[NSTaskname setLaunchPath:#"/usr/bin/automator"];
NSArray *arguments;
arguments = [NSArray arrayWithObjects:#"/Applications/appname.app/Contents/Resources/workflowname.workflow", nil];
[NSTaskname setArguments:arguments];
[NSTaskname launch];
}
The only problem is, that every single one appears behind the window of my app. Also, one workflow launches another app which also appears behind the window.
How can I fix this?
You can probably use NSRunningApplication to bring your NSTask process to the front with its PID like this...
NSRunningApplication* app = [NSRunningApplication runningApplicationWithProcessIdentifier:[NSTaskname processIdentifier]];
[app activateWithOptions: NSApplicationActivateAllWindows];
And if you need to activate a specific application, for example your workflow that launches another app, then you could do this using the application's bundle identifier. This example will activate Safari.
NSArray* apps = [NSRunningApplication runningApplicationsWithBundleIdentifier:#"com.apple.Safari"];
[(NSRunningApplication*)[apps objectAtIndex:0] activateWithOptions: NSApplicationActivateAllWindows];

NSWorkspace vs NSTask to start iTunes from a sandboxed app

I'm trying to run iTunes from my ObjectiveC app that runs in a sandbox.
Apple documentation mentions that 'child processes created with the NSTask class inherit the sandbox of the parent app'. The result is that when running iTunes, some permission error pops up and iTunes is closed.
When running it using NSWorkspace methods it does not crash and seems it's running outside any sandbox. Does that mean that i have permission to insert some dynamic library at launch time using DYLD_INSERT_LIBRARIES ?
Here's some code:
NSString* appPath = #"/Applications/iTunes.app";
// Get application URL
NSBundle *targetBundle = [NSBundle bundleWithPath:appPath];
NSURL *applicationURL = [targetBundle executableURL];
NSString* libPath = [NSHomeDirectory() stringByAppendingPathComponent:#"myLib.dylib"];
// Environment setup
NSDictionary *config = nil;
NSDictionary *env = [NSDictionary dictionaryWithObject:libPath forKey:#"DYLD_INSERT_LIBRARIES"];
NSNumber *arch = [NSNumber numberWithInt:(int)NSBundleExecutableArchitectureI386];
config = [[NSDictionary alloc] initWithObjectsAndKeys:env, NSWorkspaceLaunchConfigurationEnvironment,
arch, NSWorkspaceLaunchConfigurationArchitecture, nil];
// Launch application
[[NSWorkspace sharedWorkspace] launchApplicationAtURL:applicationURL
options:0
configuration:config
error:nil];
[config release];
When the above code runs in a sandbox iTunes starts without any lib. Any suggestion?
Thanks,
Vlad.