I want to detect when another application was installed/uninstalled and save the time to a database at the moment of execution.
I know this is possible in Android using broadcastreceiver and I want to know if this can be done in iOS using a jailBroken device because I believe this is not possible in a non-jailBroken device.
I hope someone could help me. Thank you.
Recently was having the same problem.
You need to write SpringBoard tweak. In it you observe notification SBInstalledApplicationsDidChangeNotification from local notification center (CFNotificationCenterGetLocalCenter or [NSNotificationCenter defaultCenter]). User info dictionary will contain:
SBInstalledApplicationsRemovedBundleIDs key contains array of bundle IDs of uninstalled applications.
SBInstalledApplicationsModifiedBundleIDs key contains array of bundle IDs of updated applications.
SBInstalledApplicationsAddedBundleIDs key contains array of bundle IDs of installed applications.
Obviously that way you can log every time applications are installed/uninstalled/updated.
You can check if an application is installed by using its bundle id
BOOL isInstalled = [[LSApplicationWorkspace defaultWorkspace] applicationIsInstalled:#"com.app.identifier"];
if (isInstalled) {
// app is installed }
else {
// app is not installed
}
EDIT:
If you want to check if an application got installed you can maybe count the items inside user of com.apple.mobile.installation.plist it holds all the information about installed apps.
You can write the number of apps inside a plist then later check back and compare the results?
// get apps count
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:#"/var/mobile/Library/Caches/com.apple.mobile.installation.plist"];
int numberOfApps = [[dict objectForKey: #"User"] count];
NSLog(#"Count: %i",numberOfApps);
// Save apps count inside a plist
NSString *path = #"/var/mobile/AppsCount.plist";
NSFileManager *fm = [NSFileManager defaultManager];
NSMutableDictionary *data;
if ([fm fileExistsAtPath:path]) {
data = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
}
else {
// If the file doesn’t exist, create an empty dictionary
data = [[NSMutableDictionary alloc] init];
}
[data setObject:[NSNumber numberWithInt:numberOfApps] forKey:#"savedAppsCount"];
[data writeToFile:path atomically:YES];
[data release];
And then to compare old counts with the new apps count:
// get current number of apps
NSString *path = #"/var/mobile/AppsCount.plist";
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:#"/var/mobile/Library/Caches/com.apple.mobile.installation.plist"];
int numberOfApps = [[dict objectForKey: #"User"] count];
// retrieve old app count and compare to new ones
NSMutableDictionary *retrieveCounts = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
int oldAppCount = [[retrieveCounts objectForKey:#"savedAppsCount"] intValue];
if (oldAppCount < numberOfApps) {
NSLog(#"NEW APP GOT INSTALLED");
}
else if (oldAppCount > numberOfApps) {
NSLog(#"AN APP GOT UNINSTALLED");
}
else {
NSLog(#"NOTHING GOT INSTALLED OR UNINSTALLED");
}
[retrieveCounts release];
But that doesn't give you the time, it just checks if a new app got installed
There might be a better way of doing that, but that's what came into my mind.
Hope it helps.
Related
- (instancetype)initWithDestinationIndex:(NSUInteger)levelsIndex {
NSString* filepath = [[NSBundle mainBundle]
pathForResource:#"Levels" ofType:#"plist"];
NSDictionary *levels = [NSDictionary dictionaryWithContentsOfFile:filepath];
NSArray *levelsArray = levels[#"LevelsData"];
_data = levelsArray[levelsIndex];
[_verticalB setToInitialStateVertical];
return self;
}
I have a plist that is supposed to load information of 18 key-value pairs. The _data of type NSDictionary instance variable (when I run the program and put a breakpoint at that line _data = levelsArray[levelsIndex];) is almost always null, except on one occasion where it is actually had the 18 key-value pairs loaded. Any thoughts as to why it pretty much always is null?
I pass in 0 for my levelsIndex, and the 'LevelsData' is the NSArray that holds the 18 key-value pair dictionaries.
if your _data is NSMutableDictionary use the below code,
NSMutableDictionary *_data = [[NSMutableDictionary alloc] init];
[_data setObject:[levelsArray objectAtIndex: levelsIndex] forKey:[NSString stringWithFormat:#"%d", levelsIndex]];
or
for(int i=0; i<[levelsArray count]; i++){
[_data setObject:[levelsArray objectAtIndex:i] forKey:[NSString stringWithFormat:#"%d",i]];
}
hope its helpful
It may possible that, you are running app in a "release" scheme. Have you double check? As long as you're getting the result.
To check,
Click on Project Name next to [Run] button. > Edit Scheme > Run > Build Configuration > Debug/Release
A tester that uses my application encountered a seemingly un-reproducable bug a few days ago. I believe the NSLogs that my application records can possibly provide information surrounding the issue, but the Xcode Organizer console only logs the 260 or so previous lines. Is there some log file located on the device that offers a more extended amount of NSLogs? The tester has a jailbroken device so accessing the root directory shouldn't be an issue.
Why don't you use PList to store the logs?
I have developed some location based apps. I always have to drive around a certain areas to test the accuracy of the Location Update, Region Monitoring and etc. I store those logs into a PList and I will analyse the logs on the PList after I completed a run.
Example Code:
-(void)addLocationToPList{
NSString *plistName = [NSString stringWithFormat:#"Location.plist"];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex:0];
NSString *fullPath = [NSString stringWithFormat:#"%#/%#", docDir, plistName];
NSMutableDictionary *savedProfile = [[NSMutableDictionary alloc] initWithContentsOfFile:fullPath];
if (!savedProfile){
savedProfile = [[NSMutableDictionary alloc] init];
self.shareModel.myCurrentLocationArray = [[NSMutableArray alloc]init];
}
else{
self.shareModel.myCurrentLocationArray = [savedProfile objectForKey:#"locationArray"];
}
if(self.shareModel.myBestLocationDictFromTracker)
{
[self.shareModel.myCurrentLocationArray addObject:self.shareModel.myBestLocationDictFromTracker];
[savedProfile setObject:self.shareModel.myCurrentLocationArray forKey:#"locationArray"];
}
if (![savedProfile writeToFile:fullPath atomically:FALSE] ) {
NSLog(#"Couldn't save Location.plist" );
}
}
I call the above function to add the location to a PList whenever there is a location update. You may use it in anyway you want based on what you really need to log.
I think it is much better than the Organizer Console log as you can extract the PList Out and keep a copy on your Mac for future analysis and etc. I am using iFunBox to access/extract the PList.
I have two UITextField
email
password
These two field values are stored in a NSMutableDictionary call userData. Now i want to save these two field values in a file, so that the records keep there and i can restore this record to check user login correctly. Here i want to accomplish that, but not working.
My code :
-(void) saveRegistrationData
{
userData = [[NSMutableDictionary alloc]
initWithObjects:[[NSMutableArray alloc] initWithObjects:#"123456", nil]
forKeys:[[NSMutableArray alloc] initWithObjects:#"admin#gmail.com", nil]];
[userData setObject:passwordTextField.text forKey:emailTextField.text];
NSString *savePath = [#"/MediaFiles/Documents/" stringByExpandingTildeInPath];
[userData writeToFile: savePath atomically: YES];
//[userData writeToFile:#"MediaFiles/Documents/" atomically:YES];
for (id key in userData)
{
NSLog(#"%# is for %#", key, [userData objectForKey:key]);
}
}
I think the path is not setting correctly. If any one similar with the solution, please share with me. Thanks in advanced. Have a good day.
It's not working for a few reasons.
1) You're writing to a folder in the root of the device's filesystem. Apple uses sandboxing to prevent this from happening as you could overwrite and modify any system files.
2) You're writing to a folder rather than a file. To write to a file, you need to specify a filename (and extension). i.e. "/MediaFiles/Documents/dnt_lk_at_dis.plist"
In order to fix these issues, you need to be firstly getting the path to the sandbox (documents directory) and then append the filepath.
NSString *docsPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filename = #"secret.plist";
NSString *filePath = [docsPath stringByAppendingPathComponent:filename];
Furthermore, I strongly suggest that you instead use the keychain for storing sensitive user information. Anybody with a jailbroken device, or anybody that has access to the file system will be able to extract the user's information if it is stored in plain-text. At the very least, please encrypt the password before writing it to disk.
-(void) saveRegistrationData
{
userData = [[NSMutableDictionary alloc] init];
[userData setObject:passwordTextField.text forKey:#"password"];
[userData setObject:emailTextField.text forKey:#"email"];
// Alternative to the above:
userData = [[NSMutableDictionary alloc]
initWithObjects:[[NSMutableArray alloc] initWithObjects:passwordTextField.text, emailTextField.text, nil]
forKeys:[[NSMutableArray alloc] initWithObjects:#"password", #"email" nil]];
NSString *savePath = [#"/MediaFiles/Documents/myDict.plist" stringByExpandingTildeInPath]; // write to a file, not a dictionary
[userData writeToFile: savePath atomically: YES];
for (id key in userData)
{
NSLog(#"%# is for %#", key, [userData objectForKey:key]); // now you should see the result that you want to.
}
// Alternative for the above - the lazy way of doing it:
NSLog (#"theDictionary: %#", userData);
}
Please forgive me any typos or so. I did not compile it for you :-)
Trying to read a plist and change my font color depending on the option that was selected in the following settings bundle.
The following is how I am trying to accomplish it:
NSString *path = #"/var/mobile/Library/Preferences/NCNotes.plist";
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path];
fontSize = [[dict objectForKey:#"slideSwitched"] floatValue];
if ([[dict objectForKey:#"noteColor"] valueForKey:#"Purple"]) {
noteView.textColor = [UIColor purpleColor];
} else {
noteView.textColor = [UIColor blackColor];
}
Any ideas why this is why my app is crashing? How do I read the values and change the color depending on what was selected?
It appears that the top level of your plist is an array, not a dictionary, because at the top it says "Item 1" where all of your content is within that. So you have a dictionary within an array. So you can change your code like this:
NSString *path = #"/var/mobile/Library/Preferences/NCNotes.plist";
NSArray *array = [[NSArray alloc] initWithContentsOfFile:path];
NSDictionary *dict = array[0];
You could also change the structure of your plist so that you have a dictionary as the root instead of an array.
Also, keys are supposed to be on the left-hand side and their values on the right-hand side, so I don't see a key "noteColor". You have a key "key" with a value "noteColor", so you'll need to make that correction. I'm also not seeing a "slideSwitched" key, though it might just be outside the bounds of your screenshot.
Also the following won't work:
[[dict objectForKey:#"noteColor"] valueForKey:#"Purple"]
Whatever you get from [dict objectForKey:#"noteColor"] isn't going to be a dictionary, so calling valueForKey: on that isn't going to give you what you want.
simply you should do this with document directory
NSString *contentPath=[[NSBundle mainBundle] pathForResource:#"PLIST_FILE_NAME" ofType:#"plist"];
NSDictionary *dictionary=[NSDictionary dictionaryWithContentsOfFile:contentPath];
write your logic after this, wait a minute , its seems like you dont have a key "noteColor" also. check your plist
Here is some example code documented up the wazoo. Hopefully it will help you understand how these plists and dictionaries work. Everything will be based on your plist file (which could definitely be improved upon, but that's up to you as I don't know your specific situation).
Your question is "How do I find color based on user selection?" I will assume you get the user selection as an int. Something like "User selected 7".
//Load your plist dictionary
NSString *path = #"/var/mobile/Library/Preferences/NCNotes.plist";
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path];
//Get the array of validValues and the array of validTitles
NSArray *valuesArray = [dict objectForKey:#"validValues"];
NSArray *titlesArray = [dict objectForKey:#"validTitles"];
//Now get the user selected index from the validValues array
int arraySelection = -1;
for(int i = 0; i < [valuesArray count]; i++)
{
NSNumber *number = [valuesArray objectAtIndex:i];
if([number intValue] == userSelectedInput)
{
arraySelection = i;
break;
}
}
if(arraySelection == -1)
{
//Not found in array
return;
}
//Now with that index get the title of the object that the user selected
NSString *userSelectedTitle = [titlesArray objectAtIndex:arraySelection];
//Now do your checking on what the user selected based on that:
if([userSelectedTitle isEqualToString:#"Purple"])
...
You could boil this down quite a bit. Currently your validValues array is completely useless. If it were out of order or missing numbers then it would be needed, but straight counting can be achieved by the validTitles array.
I'm developing an app that should search a string inside the Plist data and return a value that should prompt the user what kind of, say brand it is. For example, the user inputs "iPhone" in my text field and the app should return the brand of the product the user inputted after tapping the Go button below the text field.
Inside my Products.plist, It contains arrays of brands with certain products that brand has. Example would be:
Apple: iPhone, iPod, iPad, Mac
Sony: PSP, PS3, Bravia, Xperia
Samsung: Galaxy S II, Galaxy S III, Galaxy Tab
How can I do this? I have already done my app working fine but without using a plist. I just want to use a Plist for the app to be easily maintained and updated.
Consider your plist file is called data.plist, this is how you should do this:
NSBundle *bundle = [NSBundle mainBundle];
NSString *pListpath = [bundle pathForResource:#"data" ofType:#"plist"];
NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:pListpath];
for (NSString* key in [dictionary allKeys]){
NSArray *array = [dictionary objectForKey:key];
for (int j = 0; j < [array count]; j++) {
if ([[array objectAtIndex:j] isEqualToString:#"iPhone"]) {
NSLog(#"%#",key);
}
}
}