How to create .plist file under /Library/LaunchAgents - objective-c

I'm trying to develop a launch agent for macOS via Apple Doc
https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html
One of my requirements is that the agent should work for all users. What I understood from above document is I have to put my .plist under "/Library/LaunchAgents" folder.
When I try to create this file programatically nothing happens with the below code.
NSMutableDictionary *plist = [[NSMutableDictionary alloc] init];
[plist setObject:#"test" forKey: #"test 1"];
NSString *userLaunchAgentsPath = [[NSString alloc] initWithFormat:#"%#", #"/Library/LaunchAgents/com.xxx.agent.plist"];
[plist writeToFile:userLaunchAgentsPath atomically:YES];
Probably the reason is a privilege issue. Do you have any ideas for solving this issue?

As to privileges, the plist should be owned by root and if you want the app to run as a different user, you can do that easily by providing the username/password in the plist. Your app is probably not running as root.

Related

Write NSDictionary to ONLINE .plist. Is it possible?

I'm writing an app for instant messaging aaand I'm stuck.
I am able to read data (dictionary) from plist that's on my dropbox, but I can't modify it from my app, what is a thing I actually want to achieve.
Here is how I read the online .plist file:
#Implementation
NSDictionary *wholePlist;
-(void)viewDidLoad
{
wholePlist = [[NSDictionary alloc]initWithContentsOfURL: [NSURL URLWithString:[NSString stringWithFormat:#"https://dl.dropboxusercontent.com/s/cfpree9see19t00/users.plist"]]];
self.allUsers = [wholePlist objectForKey:#"allUsers"];
} //self.allUsers is NSDictionary, also.
And this is how I am trying to save it if I change it
- (IBAction)registerButtonPressed:(UIButton *)sender {
NSString *username = self.usernameTextField.text;
NSString *password = self.setPassTextField.text;
NSMutableArray *myContacts = [[NSMutableArray alloc]init];
NSMutableArray *inbox = [[NSMutableArray alloc]init];
NSDictionary *user = [[NSDictionary alloc]initWithObjects:#[username, password, myContacts, inbox] forKeys:#[#"username",#"pass",#"myContacts",#"inbox"]];
if ([user isEqualToDictionary:[self.allUsers objectForKey:username]]) {
[[[UIAlertView alloc]initWithTitle:#"Registration error" message:#"Username already taken. Please, choose another username." delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK", nil]show];
} else {
NSURL *plistURL = [NSURL URLWithString:[NSString stringWithFormat:#"https://dl.dropboxusercontent.com/s/cfpree9see19t00/users.plist"]];
[self.allUsers setValue:user forKey:username];
[self.allUsers writeToURL:plistURL atomically:YES];
}
}
If I do it locally/offline (in some folder inside my Mac or app directory) using writeToFile: it works. When I use writeToURL: it doesn't work.
My questions are:
Is this even possible, what am I trying to achieve?
Is it possible with any other storage client?
If it's possible with some other storage client, please give me source link on how to OR explain how to.
Thanks!
Instant messaging applications are almost always best done using sockets. I'd HIGHLY recommend against using a file on a server to read and write from. While it's possible, you're asking for a world of pain and slugish-ness.
So to answer your questions in a striaght forward manner:
Yes... Don't do it.
Yes. of course you can use CloudKit either the DB or file upload part. Again, I recommend against this method because it's slow and has high overhead on the network.
I highly recommend reading up on sockets: http://en.wikipedia.org/wiki/Network_socket to better understand this approach. I have a chat socket written in C++. However it does a bit more than what you may need: https://github.com/theMonster/ModularServer. Also, there's a very popular chat server example for node.js here: http://socket.io/get-started/chat/
Let me know if you have any questions.

Objective c save to my plist

I have the plist file under the resources folder which is name is logical-app.plist
In ios8 if you want Gps will work then NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription keys should be added into the Info.plist
I want to add NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription keys in code in my appdelegate class.
Im trying to add the following code for solving this issue:
//write
filePath = #"/System/Library/CoreServices/SystemVersion.plist";
plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];
[plistDict setValue:#"1.1.1" forKey:#"NSLocationWhenInUseUsageDescription"];
[plistDict writeToFile:filePath atomically: YES];
//endwrite
//read plist
filePath = #"/System/Library/CoreServices/SystemVersion.plist";
plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];
value = [plistDict objectForKey:#"NSLocationWhenInUseUsageDescription"];
im trying to get
filePath = [[NSBundle mainBundle] pathForResource:#"ClickMobileCDV-Info" ofType:#"plist"];
and it is nil too....
But with no success.... when i read it from the plist it was nil...
How can i solve this issue?
You've completely got the wrong end of the stick. In order to add NSLocationAlwaysUsageDescription and NSLocationWhenInUseUsageDescription, you edit the app's plist file within Xcode and it's included in the app bundle.
There is no code needed to read/write system .plist files at runtime (the writing of which would fail anyway, due to permission errors).

NSTask works in xcode run but not when i run it outside xcode

I have created this app that make use of the /usr/bin/say command in OS X.
This method takes the value from a textfield and uses "say" to save it.
But when i run this outside xcode. I don't get the saved file.
- (IBAction)save:(id)sender
{
NSString *path;
path = #"/usr/bin/say";
NSArray *args;
args = [NSArray arrayWithObjects: #"-o", #"text.wav", #"--data-format=LEF32#8000", [textField stringValue], nil];
[[NSTask launchedTaskWithLaunchPath:path arguments:args] waitUntilExit];
NSLog(#"Saved");
}
Anyone know what i'm doing wrong?
Perhaps it's being saved but you don't know where. The path text.wav is a partial path, so it's going to be saved in the "current directory". But what directory is the "current directory"? You probably don't know.

How to populate a UITableView from a remote .plist file

Sorry if this has been asked many times before, but nothing seemed to help my issue.
I have set up my app to work perfectly reading from local .plist files from within the app itself for testing purposes, but for the app to be of any use, I need to be able to update it on a web server and load it remotely.
Here is my current code for local plists.
How would I amend this with minimum changes elsewhere in the app?
Many thanks in advance.
- (void)viewDidLoad
{
[super viewDidLoad];
//Create a dictionary with the contents of Squad.plist
NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"Squad" ofType:#"plist"]];
//Fill the Squad array with contents of dictionary under the key "Players"
[self setSquad:(NSArray*) [dictionary objectForKey:#"Players"]];
//Reload the table data
[[self tableView] reloadData];
[[self navigationItem] setPrompt:nil];
}
You will need to first download your remote .plist while showing a loading or something, and after it's downloaded, use it locally the same way you are doing now. There's no way to read it remotely.

I want to delete all items in my self created KeyChain on Mac OS X

I'm writing a little tool to synchronize passwords. I'm using my own KeyChain for this purpose. Prior to saving, I want to clear this KeyChain. However, it seems I don't understand how to use the SecItemDelete function.
NSMutableDictionary *deleteQuery = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
kSecClassGenericPassword, kSecClass,
kSecMatchLimit, kSecMatchLimitAll, nil];
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)deleteQuery);
NSLog(#"%#", SecCopyErrorMessageString(status, NULL));
This is what I've written so far, but unfortunately my items (called Root.Foo and Root.Bar) remain in the KeyChain. Also I'm wondering, how this function knows, which KeyChain should be searched? Most examples I'm fonding are about iOS, where every Application has it own KeyChain by default.
Thanks for any help :)
Solved it:
I've missed passing in an array of KeyChains to look for! It seems on iOS, always the default KeyChain of an app is used but on Mac OS you need to specify the KeyChain, as an array containing SecKeychainRefs:
NSMutableDictionary *q = [NSMutableDictionary dictionary];
[q setObject:kSecClassGenericPassword forKey:kSecClass];
[q setObject:[NSArray arrayWithObject:(__bridge id)keyChain] forKey:kSecMatchSearchList];
[q setObject:kSecMatchLimitAll forKey:kSecMatchLimit];
SecItemDelete((__bridge CFDictionaryRef)q);
This code worked perfectly.