First Issue: No Sandboxing
I am having an issue with some code to copy a file. With sandboxing turned off completely and this code.
- (IBAction)installWidget:(id)sender
{
// copy widgets to users library
NSError* error = nil;
NSString *testUrl = #"~/Library/Widgets/test.wdgt";
if ([[NSFileManager defaultManager]fileExistsAtPath:testUrl]) {
NSLog(#"yes");
}
NSString *testUrl2 = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent: #"test.wdgt"];
if ([[NSFileManager defaultManager]fileExistsAtPath:testUrl2]) {
NSLog(#"yes");
}
[[NSFileManager defaultManager] removeItemAtPath:testUrl error:nil];
[[NSFileManager defaultManager]copyItemAtPath:testUrl2 toPath:testUrl error:&error];
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
}
With sandboxing turned off I get the following error.
The file “test.wdgt” doesn’t exist. I tried zipping it thinking it was a flat file issue when changing the code from test.wdgt to test.zip I got the same error. The file is included in the resources bundle but its not letting me copy it.
I tried moving the app from outside of the build folder, same issue. I also tried cleaning the build folder same issue.
Second Issue: With Sandboxing
I get the following error with Sandboxing enabled. You don't have permission to access the directory Widgets.
Entitlement file looks like this
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.assets.movies.read-write</key>
<true/>
<key>com.apple.security.assets.music.read-write</key>
<true/>
<key>com.apple.security.assets.pictures.read-write</key>
<true/>
<key>com.apple.security.files.downloads.read-write</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.print</key>
<true/>
<key>com.apple.security.temporary-exception.files.absolute-path.read-write</key>
<array>
<string>/Users/jon/Library/Widgets/</string>
</array>
</dict>
</plist>
I am beating my head against the wall. I tried adding a simple image and then replacing the image name with the widget name and it copied fine as long as sandboxing was disabled. I wrote a widget thats works with my app and I want to distribute it by allowing the user to install the widget by clicking a button in the app or from a menu item. Any help is appreciated.
On the non-sandbox question, you need to expand the tilde(~) before using that in a path for file system operations. One way to do this is by calling -stringByExpandingTildeInPath on the string you have created, but the best practice for getting folders like this would be to use:
NSArray *paths = NSSearchPathForDirectoriesInDomains
( NSLibraryDirectory, NSUserDomainMask, YES);
This will return an array (should only be 1 element) containing the string to the path for the User's Library directory. Then you can add your specific path elements to that by using -stringByAppendingPathComponent:.
Thus, you'd get the full path by taking:
NSString *widgetsPath = [[paths objectAtIndex: 0] stringByAppendingPathComponent:
#"Widgets"];
As for doing in the sandbox, your current code will fail due to the wrong directory, which won't have access (since ~ is being interpreted as a path component and not to replace the User's home directory). However, you obviously can't use the absolute-path exception in shipping code by enumerating every user. Chances are you will need to find another approach to installing this if you are going to be sandboxed. You may be able to just open the widget file and thus get the OS to offer to copy it for you. Otherwise, you're going to have to ask the user's permission in some way, such as by popping up an open window and passing in the path to the user's Widget folder.
I have a launch daemon and I would like it to run a function every time an application launches.
I'm currently using NSWorkspace to check for the launch of applications.
parasited.plist in /Library/LaunchDaemons/
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>parasited</string>
<key>ProgramArguments</key>
<array>
<string>/Applications/parasited</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>OnDemand</key>
<false/>
</dict>
</plist>
parasited main.m
int main(int argc, const char * argv[])
{
#autoreleasepool {
[[[NSWorkspace sharedWorkspace]notificationCenter]addObserver:[[Parasited alloc] init] selector:#selector(inject) name:NSWorkspaceDidLaunchApplicationNotification object:nil];
}
}
It seems like my process, parasited keeps restarting and I can't figure out why.
My goal is to run a function everytime an app such as "Safari, Mail, Finder, etc" launches.
Your help is appreciated!
Your application has no central run loop in which to loop and wait for notifications.
As an experiment, add a CFRunLoopRun() call after your NSWorkspace call. CFRunLoopRun will loop until the process is terminated.
See Matt Gallagher's demystifying NSApplication by recreating it post to learn more about the run loop and the role it plays in keeping your application running and processing events.
I am writing a tweak for jailbroken iOS devices and I want to be able to write this NSString "bundleID" and the integer created in my code to a plist file. The code below can do this, however, it only does this once and doesn't allow me to write it to the plist multiple times. I want to do this because the bundleID changes and should also be written to the plist. Basically what I want to do is when an app is launch the bundle id for that app (com.apple.mobilesafari) is written as the key in my plist. I then have code to work add 1 to the value every time the app is opened. So for example if I opened mobile safari four times the plist should look like this.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.mobilesafari</key>
<integer>4</integer>
<key>customText</key>
<false/>
<key>enabled</key>
<false/>
</dict>
</plist>
However, when I launch mobile safari four times it stays as...
<key>com.apple.mobilesafari</key> <integer>1</integer>
I also want the bundleID saved for every app. So if I open safari then contacts I want both in my plist. For example...
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.mobilesafari</key>
<integer>1</integer>
<key>customText</key>
<false/>
<key>enabled</key>
<false/>
</dict>
<dict>
<key>com.apple.contacts</key>
<integer>1</integer>
<key>customText</key>
<false/>
<key>enabled</key>
<false/>
</dict>
</plist>
Here is my objective-c code...
%hook SBApplicationIcon
-(void)launch
{
// Return original method
%orig;
// Get Bundle ID
NSString* bundleID = [self leafIdentifier];
// Print that badboy!
NSLog(#"Bundle ID: %# ",bundleID);
// Set up plist
NSMutableDictionary *launches = [[NSMutableDictionary alloc] initWithContentsOfFile:#"/var/mobile/Library/Preferences/com.bengerard.ipslider.plist"];
// Check plist exists
NSString *pathToFile = #"/var/mobile/Library/Preferences/com.bengerard.apppop.plist";
BOOL isFile = [[NSFileManager defaultManager] fileExistsAtPath:pathToFile isDirectory:NO];
if(isFile)
{
// Counting
int count = [[launches objectForKey:bundleID] intValue];
count++;
// Write number of launches to plist
[launches setObject:[NSNumber numberWithInt:count] forKey:bundleID];
//[launches insertObject:[NSNumber numberWithInt:count] forKey:bundleID];
[launches writeToFile:#"/var/mobile/Library/Preferences/com.bengerard.apppop.plist" atomically:YES];
}
else {
//The file doesn't exit.
}
// [bundleID release];
// [pathToFile release];
// [launches release];
}
%end
P.S: I am also using theos by DHowett to compile my tweak.
Edit: Realised my two plists are different. Probably causing my problem. I will test later
I am writing an app that copies a plist into the docsdir and then reads it into a mutable array. The code below, however, returns a count of 0 for the array. The line with the dictionary log, however, returns the correct items. I have also verified that the file is being copied to the docsdir.
-(NSString *)docsDir {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *listPath = [[self docsDir]stringByAppendingPathComponent:#"list.plist"];
if (![[NSFileManager defaultManager]fileExistsAtPath:listPath]) {
[[NSFileManager defaultManager]copyItemAtPath:[[NSBundle mainBundle]pathForResource:#"list" ofType:#"plist"] toPath:listPath error:nil];
NSLog(#"Chicken");
}
NSLog(#"%#", [NSDictionary dictionaryWithContentsOfFile:listPath]);
_array = [NSArray arrayWithContentsOfFile:listPath];
NSLog(#"Count: %i", [_array count]);
}
- (void)viewDidUnload
{
[super viewDidUnload];
/ / Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
Usually this is because by default root element in plist files is a Dictionary.
Right click and select Open as Source Code, your file may look like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>foo</key>
<array>
<string>foo1</string>
<string>foo2</string>
<string>foo3</string>
</array>
</dict>
</plist>
where the root element is a dict, change it to:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<string>foo1</string>
<string>foo2</string>
<string>foo3</string>
</array>
</plist>
where the root element is an array. You can now edit as usual.
Open the plist file with Xcode.
Just find the 'key' at the top left corner and Type of the plist.
Make sure the Type is Array.
I think your plist is a dictionary that contains an array.
Try this
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:listPath]
NSArray *array = [dict objectForKey:#"key"];
Plists are usually saved a dictionaries:
Here's an example :
<dict>
<key>tiltingAnim</key>
<dict>
<key>filenamePrefix</key>
<string>radar_</string>
<key>delay</key>
<real>0.25</real>
<key>animationFrames</key>
<string>1,2,3,4,5,5,4,3,2,1,2,3,4,5</string>
</dict>
<key>takingAHitAnim</key>
<dict>
<key>filenamePrefix</key>
<string>radar_</string>
<key>delay</key>
<real>0.1</real>
<key>animationFrames</key>
<string>5,5,7,8,8</string>
</dict>
<key>blowingUpAnim</key>
<dict>
<key>filenamePrefix</key>
<string>radar_</string>
<key>delay</key>
<real>0.2</real>
<key>animationFrames</key>
<string>5,6,7,8,9,10,11,12,13,14,15,16,17</string>
</dict>
<key>transmittingAnim</key>
<dict>
<key>filenamePrefix</key>
<string>radar_</string>
<key>delay</key>
<real>0.3</real>
<key>animationFrames</key>
<string>5,6,5,6,5,6,5</string>
</dict>
</dict>
Now, there are 2 solutions to your question.
Either get the contents into a dictionary then take out the array for a specific key.
Open up the plist with a text editor and change the root key into then change root into . If your plist is static and in the bundle resources then you could do this but if it's a plist generated by your code then i wouldn't recommend this.
I am trying to create an NSMutableDictionary containing a list of animals in my iOS app with this function.
// puts animals into dictionary
- (void) putAnimalsFromPlistToDictionary
{
NSBundle *bundle = [NSBundle mainBundle];
NSString *path = [bundle pathForResource:#"myAnimals" ofType:#"plist"];
myAnimalDictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
// I set a breakpoint here in XCode.
}
I dragged myAnimals.plist (which looks like the below) into my supporting files folder for my application.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<string>elephant</string>
<string>monkey</string>
<string>cat</string>
</array>
</plist>
However, when I reach the breakpoint (as listed in my comment), I see that myAnimalDictionary is nil. Why?
Perhaps it's because you have an array in your .plist but you're trying to instantiate a mutable dictionary instance.