I am making my First MobileSubstrate Tweak For the iPhone Running IOS 7.
I am using this tutorial.
This tutorial explains the basics of Hooking and providers a git hub example of his source code.
To test the code he wrote worked and to get my head round theos compiling terminal I compiled his project.
The project is suppose to show a UIAlert when an application is launched and put a setting switching with the state of on or off within the settings application in the iPhone.
When installing this compiled deb onto my iphone the setting page is added so i can turn the function on or off but when the function is ON the alert does not show.
Here is my Tweak.xm code:
#interface SBApplicationIcon
-(void)launch;
-(id)displayName;
#end
%hook SBApplicationIcon
-(void)launch
{
NSString *appName = [self displayName];
NSMutableDictionary *settings = [NSMutableDictionary dictionaryWithContentsOfFile:
[NSString stringWithFormat:#"%#/Library/Preferences/%#", NSHomeDirectory(), #"com.AndyIbanez.NotifierSettings.plist"]];
NSNumber* shouldNotify = [settings objectForKey:#"alertLaunch"];
if([shouldNotify boolValue] == YES)
{
NSString *message = [NSString stringWithFormat:#"The app %# has been launched", appName, nil];
UIAlertView *alert1 = [[UIAlertView alloc] initWithTitle:appName message:message delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert1 show];
[alert1 release];
}
%orig;
}
%end
Here is the GitHub Example File I am following and compelling: https://github.com/AndyIbanez/TutorialProjects/tree/master/launchnotifier
launch is for iOS 6 and you need to use launchFromLocation: on iOS 7.
#interface SBIcon : NSObject
- (void)launch; // iOS 6
- (void)launchFromLocation:(NSInteger)location; //iOS 7
#end
Related
I am fairly new to jailbreak iOS development and had a question. I am trying to send a message between two processes(MobileSafari to SpringBoard) and am having a problem, the reciever function in SpringBoard is never called! So far in SpringBoard I have this:
-(void)applicationDidFinishLaunching:(id)arg1{
%orig(arg1);
//register for notifications
CPDistributedMessagingCenter *messagingCenter = [CPDistributedMessagingCenter centerNamed:#"com.magnusdevelopment.flow"];
[messagingCenter runServerOnCurrentThread];
[messagingCenter registerForMessageName:#"updateWallpaper" target:self selector:#selector(handleMessageNamed:withUserInfo:)];
[messagingCenter registerForMessageName:#"updateScalingMode" target:self selector:#selector(handleMessageNamed:withUserInfo:)];
[messagingCenter registerForMessageName:#"downloadWallpaper" target:self selector:#selector(handleMessageNamed:withUserInfo:)];
UIAlertView *testAlert = [[UIAlertView alloc] initWithTitle:#"Yo!" message:#"registered" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[testAlert show];
}
}
%new
-(NSDictionary *)handleMessageNamed:(NSString *)name withUserInfo:(NSDictionary *)userInfo{
UIAlertView *testAlert = [[UIAlertView alloc] initWithTitle:#"Yo!" message:#"2" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[testAlert show];
if([name isEqualToString:#"updateWallpaper"]){
//get info for wallpaper
NSString *wallpaperImagePath = [userInfo objectForKey:#"WALLPAPER_PATH"];
int option = [[userInfo objectForKey:#"OPTION"] intValue];
BOOL retValue = setWallpaperImage(wallpaperImagePath, option);
//return the dictionary
NSMutableDictionary *replyDict = [[NSMutableDictionary alloc] init];
[replyDict setObject:[NSString stringWithFormat:#"%hhd",retValue] forKey:#"RETURN_VALUE"];
return replyDict;
}else if([name isEqualToString:#"updateScalingMode"]){
//get info from dictionary
int option = [[userInfo objectForKey:#"OPTION"] intValue];
NSString *scalingMode = [userInfo objectForKey:#"SCALING_MODE"];
//set wallpaper scaling mode
setWallpaperScalingMode(scalingMode,option);
}//end if
return nil;
}//end method
and when a button is pressed in MobileSafari I call this code:
NSString *option = [NSString stringWithFormat:#"%i",wallpaperOption];
NSDictionary *infoDict = [NSDictionary dictionaryWithObjectsAndKeys: wallpaperPath, #"WALLPAPER_PATH", option, #"OPTION", nil];
CPDistributedMessagingCenter *messagingCenter = [CPDistributedMessagingCenter centerNamed:#"com.magnusdevelopment.flow"];
[messagingCenter sendMessageAndReceiveReplyName:#"downloadWallpaper" userInfo:infoDict];
UIAlertView *testAlert = [[UIAlertView alloc] initWithTitle:#"Yo!" message:#"sent" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[testAlert show];
I get the alert "registered" whenever SpringBoard starts up and then when I press the button I get the message "sent". The only thing that isn't called is the function handleMessageNamed:withUserInfo:
Why isn't this working?
Thanks!
Try darwin notifications https://developer.apple.com/library/mac/documentation/corefoundation/Reference/CFNotificationCenterRef/Reference/reference.html It's a public API, shouldn't be hard to find sample code.
If you look at this document entitled "Updating extensions for iOS 7, it looks there are problems using CPDistributedMessagingCenter on iOS 7, but Ryan Petrich has published a library that may help you work around them:
Inter-process communication
CPDistributedMessagingCenter, XPC and other IPC methods built on top
of bootstrap registered mach services don't work; you get deny lookup
in the Xcode console.
Workaround: rpetrich has built a workaround called RocketBootstrap: "One common way processes communicate with each other
on iOS and OS X is through a messaging system called mach ports. Each
port is a channel that can either receive or send messages. There is a
central registration system for these ports called bootstrap, where
ports can be registered and accessed by a service name assigned to
them. Recent versions of iOS restrict which names a process can
access—MobileMail, MobileSafari and App Store apps are only allowed to
access a very specific set of services that come with iOS.
RocketBootstrap adds a secondary lookup service that doesn't restrict
which processes can access which services."
In iOS app,
Anytime I call this function to open app store,
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"itms-apps://app-url"]];
The Original app will be deactivated.
The user will then have to restart the original app after they exit the App Store.
It’s very inconvenient way of installation.
Is there any way to open App Store links without leaving the app?
For example, opened as popup window,
after installation just close the popup window, and I can see the original app.
Updated :
I found a great example!
Like this game's popup.
Yes, we can open an App store link without leaving the existing app in IOS 6+.
you can use below for it.
#import <StoreKit/StoreKit.h>
SKStoreProductViewController *storeController = [[SKStoreProductViewController alloc] init];
storeController.delegate = delegate;
NSDictionary *productParameters = #{ SKStoreProductParameterITunesItemIdentifier : appStoreID };
[storeController loadProductWithParameters:productParameters completionBlock:^(BOOL result, NSError *error) {
//Handle response
}
Thanks
My version is here.
1) #import <StoreKit/StoreKit.h> and set SKStoreProductViewControllerDelegate
2) add delegate response method,
- (void)productViewControllerDidFinish:(SKStoreProductViewController *)viewController
{
// if user do cancel, close it
[viewController dismissViewControllerAnimated:YES completion:nil];
}
3) add store open code.
void SomeClassName::openAppStore(string appStoreId, string appUrl)
{
// below iOS 6.0
NSString *appUrlStatic = [NSString stringWithUTF8String:appUrl.c_str()];
// iOS 6.0 or above, appstore id is 9-digin number
NSString *appId = [NSString stringWithUTF8String:appStoreId.c_str()];;
// check SKStoreProductViewController API exist or not
if(NSClassFromString(#"SKStoreProductViewController")) {
SKStoreProductViewController *storeController = [[SKStoreProductViewController alloc] init];
storeController.delegate = self;
NSDictionary *productParameters = #{ SKStoreProductParameterITunesItemIdentifier : appId };
[storeController loadProductWithParameters:productParameters completionBlock:^(BOOL result, NSError *error) {
if (result) {
[self presentViewController:storeController animated:YES completion:nil];
} else {
[[[UIAlertView alloc] initWithTitle:#"Error Occur"
message:#"Error to open App Store."
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles: nil] show];
}
}];
[storeController release];
} else {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:appUrlStatic]];
}
}
EDIT: The error is with the data structures that are being used during PDF generation. I'll be able to debug it once I can get a copy of OSX that supports iOS7. Thanks for all the help everyone!
At work I have Mac dedicated to working on iOS 6 apps. So far it hasn't been possible to update to a newer version of OSX so my version of XCode can't be upgraded to support iOS7 naturally. So long story short I can't debug iOS7 apps, so I am not sure why the app is crashing.
I have a UIActionSheet. I used to be using one with those completion blocks but was trying to debug so I have stripped everything away to just the basic barebones and it still crashes when I click on the button.
UIActionSheet* actionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:nil cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:#"Send by Email", #"Send To...", #"Open In...", nil ];
[actionSheet showFromBarButtonItem:sender animated:YES];
That's just sitting on the end of a PDF generation method.
Any ideas? I've been researching this all afternoon and I haven't found any reason why it would stop working like this. I did try storing the action sheet as data in the view controller so the reference was being kept, but to no avail.
I am using ARC.
EDIT: I tried an UIAlertView with the same results. Maybe it's the PDF context ruining things somehow?
Thanks for all the help everyone.
EDIT: Big breakthrough in solving this one: When commenting out my PDF generation code that's before my action sheet/modal dialog/alert view, it opens without complaint. So it's some kind of hybrid issue, and I'll post the majority of my method here so everybody can see what's up:
-(void)shareTapped:(id)sender
{
if (actionSheet.isVisible)
return;
if (![MFMailComposeViewController canSendMail])
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No mail setup" message:#"You must setup your email in the main settings app before you can share." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
return;
}
for( NSIndexPath *indexPath in self.tableView.indexPathsForSelectedRows )
{
// should only get run once due to UI
Calculation* calc = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSString *filename = [calc.name stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *path = [[[[self applicationDocumentsDirectory] path] stringByAppendingPathComponent:filename] stringByAppendingPathExtension:#"ipc"];
[[PPCalculation sharedInstance] openCalculation:path];
}
[[PPCalculation sharedInstance] calculate];
// let's generate the PDF here!
NSMutableData* pdfData = [[NSMutableData alloc] init];
UIGraphicsBeginPDFContextToData( pdfData, CGRectZero, nil );
UIGraphicsBeginPDFPage();
// 200 lines of drawing commands here
UIGraphicsEndPDFContext();
// save to file
NSString* path;
for( NSIndexPath *indexPath in self.tableView.indexPathsForSelectedRows )
{
// should only get run once due to UI
Calculation* calc = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSString* filename = [calc.name stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
path = [[[[self applicationDocumentsDirectory] path] stringByAppendingPathComponent:filename] stringByAppendingPathExtension:#"pdf"];
[[NSFileManager defaultManager] createFileAtPath:path
contents:pdfData
attributes:nil];
}
// ActionSheet, modal dialog, composer dialog, alert view, all of them crash when I try to put them here
UIActionSheet* sheet = [[UIActionSheet alloc] initWithTitle:#"Share" delegate:nil cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:#"Send By Email", nil];
[sheet showFromBarButtonItem:sender animated:YES];
}
Thanks again guys.
EDIT: It seems that, from my investigation and commenting things out line by line and sending them to the device over TestFlight that it's the internal data structures somehow not working properly, which is strange, as the rest of the app works fine. I probably will get a copy of Mountain Lion or something so I can debug this thing properly.
Try below code... May be it will help you...
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:#"Send by Email", #"Send To...", #"Open In...", nil];
//actionSheet.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
actionSheet.actionSheetStyle = UIActionSheetStyleBlackTranslucent;
actionSheet.tag = ((UIButton*)sender).tag;
[actionSheet showFromRect:[(UIButton*)sender frame] inView:[(UIButton*)sender superview] animated:YES];
By sheer trial and error and commenting out code, I have narrowed it down to the PDF generation itself. Somewhere in the guts of the C++ data structures something is happening that is making iOS7 sad but the others fine. I've managed to convince the boss to order Mountain Lion so once that arrives I can build for iOS7 directly and debug it properly.
Try This it will help yo
your barbutton action method :
UIActionSheet* actionSheet = [[UIActionSheet alloc] initWithTitle:nil: delegate:nil cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:#"Send by Email", #"Send To...", #"Open In...", nil ];
[actionSheet showInView:self.view];
I'm building an app that allows the user to export en import data files and send them by e-mail.
So I've created a data file type with extension ".myAppExtension".
At first time everythings goes well. I can't export and send an e-mail. And when I open the e-mail, the method does work.
-(BOOL) application:(UIApplication *)application handleOpenURL:(NSURL *)url {
if (url != nil && [url isFileURL]) {
NSLog(#"%#",url);
NSLog(#"%#",[url pathExtension]);
if([[[url pathExtension] lowercaseString] isEqualToString:[#"myAppExtension" lowercaseString]]){
//Deal with received file
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Export ok" message:[NSString stringWithFormat:#"This file has been added : %#",[url lastPathComponent]] delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil,nil];
[alert show];
}else{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Export failed" message:[NSString stringWithFormat:#"This extention is not supported : %#",[url pathExtension]] delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil,nil];
[alert show];
}
}
return YES;
}
My issue is that when I want to export an other type of file with extension "otherExtension". I did not create data type for this extension in my app.
So I export and send an e-mail with this second type of file. The file name showed in e-mail "file.otherExtension". But, this is the issue, when I tap this mail attachement the e-mail app offers me to open it in my application. That's not what I want and, as I said, I did not create the data type for "otherExtension".
Edit : This is how I created the file type in myApp-info.plist :
If someone is interested, the issue were from the send e-mail fonction.
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init] ;
[picker setSubject:mailSubject];
[picker addAttachmentData:codedData mimeType:#"application/myApp" fileName:[filePath lastPathComponent]];
[picker setToRecipients:[NSArray array]];
[picker setMessageBody:mailBody isHTML:NO];
[picker setMailComposeDelegate:self];
[currentMainViewController presentViewController:picker animated:YES completion:nil];
By adding the mime type to mail attachment the receiving application was using it to read the file. Replacing the mime type by "nil" solved my issue.
[picker addAttachmentData:codedData mimeType:nil fileName:[filePath lastPathComponent]];
Im following Ray Wenderlich tutorial for instruments, but I don't know why the profiling is not showing the leaked object??
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString * sushiName = [_sushiTypes objectAtIndex:indexPath.row];
NSString * sushiString = [NSString stringWithFormat:#"%d: %#", indexPath.row, sushiName];
NSString * message = [NSString stringWithFormat:#"Last sushi: %#. Cur sushi: %#", _lastSushiSelected, sushiString];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Sushi Power!"
message:message
delegate:nil
cancelButtonTitle:nil
otherButtonTitles:#"OK", nil];
[alertView show];
//_lastSushiSelected = sushiString; //el que jode, pues lo pone en string deallocada, por strinWithFormat que usa autorelease!
_lastSushiSelected = [sushiString retain];
//[alertView release];
}
Im using the code in the tutorial, and as you can see the alertView is leaking!
But I run it trough instruments leaks, and nothing appears! [also is very very very slow to acknowledge the stop button was pressed to stop the profiling!]
So what is missing??,
thanks a lot!
Frankly, I think it's a bug. Hopefully it'll be fixed soon (I'm using v4.1) but all is not lost. Under the Allocations instrument you can filter which types are displayed. In this image I've told it to show UIAlertView instances. After clicking in the UITableView a couple of times you can see it tells me that there are 2 instances living, which confirms that there is a leak.