I would appreciate help in creating an iOS app to run a specified script at /var/mobile/script.sh. The script I have written opens a number of specified apps "all at once" on my jailbroken 6.1.2 iphone. Currently I run the script by starting MobileTerminal and manually running the script.sh file from the command line. I would like to be able to create an app that I could start via the Springboard which would run /var/mobile/script.sh directly.
I do not have a Mac and so I am unable to compile an app myself. I also do not have much experience of programming so I would appreciate any help on offer. I have seen an answer which is similar: iOS execute shell script from Activator
The answer provided above is VERY close to what I am looking for. However I have two problems with the Script.app as it stands:
1) As the script I have written opens a number of other apps which takes around two minutes to complete, the Script.app is automatically killed by iOS after about 20 seconds. I'm not sure if a flag "didFinishLaunchingWithOptions" needs to be set to allow Script.app to continue running so it can finish running my script? I have installed a package via Cydia called "Background Manager" - [which as I understand it makes all apps effectively think they are running in the foreground].
2) I have previously tested Script.app listed above on iOS 5 and the Script.app did run for around 20 seconds bringing the apps to the foreground as listed in my script.sh. On iOS 6.1.2 the Script.app runs certain commands in script.sh [e.g. killall commands] but when it comes to opening a specified app via the script it won't open any app [there is a blank black screen for 20 seconds and then the Script app closes without having opened any apps via the script.sh file]. However in iOS 6.1.2 if Script.app is started and immediately the home button is pressed to return you to the Springboard the Script.app will open apps via my script.sh for the first 20 seconds, so there appears to be a difference between the way the Script.app runs on iOS5 vs iOS6. I would like if Script.app could open apps via the script.sh without me having to immediately press the home button after Script.app starts on iOS 6
In my script file I use a command line package called "open" to specific which app to open via its CFBundleIdentifier: http://moreinfo.thebigboss.org/moreinfo/depiction.php?file=openData
Thanks for your help
Here's a technique that should work for you. It's not necessarily the way I'd solve it, but the solution is designed to work around you not having a Mac / Xcode.
One problem is that iOS expects normal "apps" to startup quickly, and begin responding to normal UI application events. If you use my original script launcher, it does not actually create a UIApplication, but simply calls system() from the main program. Assuming the call to system() completes quickly, there's no problem. But, if your script takes 20 seconds to run, that's too long, and iOS will kill the app.
You could build a normal UI application, calling UIApplicationMain(), and starting your long-running script after the app finishes startup. But really, you're not building an app. You simply want to use a SpringBoard icon to kick off a script. So, I don't think that solution makes a lot of sense.
What you probably want is a non-graphical daemon to run your long script for you. For this, you could build a Launch Daemon, and that might be how I solved the problem. But, without Xcode, that's tough. Another option is to take advantage of the privileged daemon that SBSettings has. You can use it to run your script. Then, your "app" need only fire off a notification to tell SBSettings to run that script. It can then exit, almost immediately.
Here is a pre-built binary that invokes a script named com.mycompany.script (get version 1.1). Install this app on your iPhone (it can be installed normally, in the sandbox area).
Then, you'll need to put your script at (this exact path and filename):
/var/mobile/Library/SBSettings/Commands/com.mycompany.script
For example, its contents might be:
#!/bin/sh
/usr/bin/open com.mycompany.AppOne
/usr/bin/open com.mycompany.AppTwo
/usr/bin/open com.mycompany.AppThree
exit 0;
where you're passing app bundle IDs to open. You can put whatever you want inside it. Make sure to login to your iPhone and set the right permissions on your script:
cd /var/mobile/Library/SBSettings/Commands/
chmod 755 com.mycompany.script
chown mobile.mobile com.mycompany.script
and then reboot (re-springing might be enough to get SBSettings to recognize your new script).
Note: for those who are coders, the main program of this app basically just contains this code:
#include <notify.h>
int main(int argc, char *argv[])
{
notify_post("com.mycompany.script");
return 0;
}
Related
I have a question which seems like it should be a fairly common occurrence. I am trying to test code which only runs the first time an ios application is installed. While in principle this is very easy, I'm having trouble with it behaving properly the second time the app runs (note, this is not crash related).
I have been force running the app for a second time using the "Application does not run in background" flag in the plist, and then just hitting the home button. This works great, except i stop getting log data after the first run.
Does anyone know how to test for this situation in a way where you can continue seeing the log information after the app closes? For example, if there is a way to attach the xcode logger to the new process id? Or just another way to force an app reboot without losing the logging feature?
Thanks in advance!
Use the debugger menu:
Product>Attach To Process
(Results may vary with different versions of Xcode).
Also, you might need to insert a sleep at the very start of your launch to catch the very early log messages.
EDIT: If you're on a device then you can use the Device Organizer (cmd+shift+2) to watch all logs on a device.
I'm working on trying to launch an automated testing solution for some iOS applications. I'm using fruitstrap to transfer and install a compiled app over to the connected iPhone, but I'm struggling to find a way to automatically launch the application after the installation is complete.
Fruitstrap has an option to run the app in the GDB debugger, which works. Unfortunately there are some test cases which will require the app to be run without the debugger attached (special crash handling). I've spent a good amount of time muddling through the resources available on MobileDevice Library which is what Fruitstrap uses, but I haven't been able to turn anything up on launching an App.
Any ideas?
You can do what you want by using fruitstrap or Xcode to start a "bootstrap" program that causes your target application to run via a custom URL as described by Michael.
While the bootstrap program would be running under the debugger the URL-invoked program would be running normally.
Creating a bootstrap program and using URL Schemes may be an option for some people, and certainly should be considered, but it doesn't fit into my requirements.
What I ended up doing was to launch the app with the debugger through fruitstrap. I re-compiled fruitstrap to include the following prep commands (In the GDB_PREP_CMDS define):
handle all noprint pass nostop
continue
The handle will pass the signal on to the program so the custom signal handler (crash handler in this case) will handle the signal. The continue was something I needed so that the app would actually run once the debugger started.
There is one unfortunate flaw in this, which unfortunately I do not know a workaround for. The ARM7 version of GDB does not have the 'set dont_handle_bad_access' command like the darwin version does. For some reason passing EXC_BAD_ACCESS signals to the program does not work and the app hangs. This is significant since this is the signal for most crashes. But as it stands now, its the best I can do, and at least its handling uncaught exceptions.
I believe you may be looking for some sort of Custom URL Scheme.
Have a look at the following document and scroll down to: Implementing Custom URL Schemes
http://developer.apple.com/library/ios/#DOCUMENTATION/iPhone/Conceptual/iPhoneOSProgrammingGuide/AdvancedAppTricks/AdvancedAppTricks.html
You can also google URL Schemes in iOS to see if you come across something similar to what you are trying to do.
Let me know if this helped you out. Would be interesting to hear if you had any success.
Cheers.
Is there a way to bring my app to the foreground once a timer runs out? This is for a kiosk-type app that'll display some information at various points during user's session.
This is for an app that will only be installed on our enterprise devices, thus not be submitted to Apple for approval. I am also opening to exploring jailbreak options.
I'd appreciate any help/tips you guys can provide. Thanks.
Yes, you can technically use Xcode for jailbreak development (but you don't have to). If you want your app to be installed outside the normal sandbox, and in /Applications/, then you'd build with Xcode without code signing, fake code sign (or use self-signed certificate), and then copy/install the app to your device, using scp or something similar (maybe have a script for this).
You can google search on tools like "Theos", "Logos", or "iOSOpenDev", too. More here
Also, see this page for information about fake code signing with Xcode.
In terms of bringing an app to the foreground, there's at least a couple ways to handle that:
One would be to use Cydia to install the (free) utility open. With open, you can issue a command line call to open any app, by using its bundle ID (e.g. open com.mycompany.MyAppName). If you want to do this programatically, issue that command within a system() call:
#import <stdlib.h>
int returnCode = system("/usr/bin/open com.mycompany.MyAppName");
Another alternative is to see this answer by #WrightsCS. Make sure to read the comments, too, about where this goes.
Update: in terms of putting your app into the background, you can kill your app completely with either exit(0) or [[UIApplication sharedApplication] terminateWithSuccess]. Or, see this answer for a solution to programmatically simulate a home button press, which will send the app to the background without killing it.
You won't be able to use NSTimer, because timers don't fire while your app is in the background. However, you can use GCD blocks to run your background work, and make the system() call with open to bring you back to the foreground.
See this answer, probably scrolling all the way to the bottom of his post
or look at this similar answer, which was actually posted at the bottom of the question
Jailbroken options for bringing your app to the foreground:
Hook into SpringBoard using MobileSubstrate. You can find classes and methods with promising names, such as [SBApplicationIcon launch] and [SBApplication launch]. Another possibility is using SBSLaunchApplicationWithIdentifier() from the SpringBoardServices private framework.
Options for suspending the app:
You most likely can do this again by using MobileSubstrate to make SpringBoard close a particular app for you. Maybe you can simulate a home button click by calling [SBUIController handleMenuTap] or something similar.
I haven't been able to find much information about it, but I've seen a few hints that it is possible to use NSTask in an iPhone app. If it is possible, how would I go about doing so?
I don't want to jailbreak my iPhone, but the app I'm developing is for internal use only; it will not be distributed so I don't care if Apple rejects apps that use NSTask.
UPDATE: I went ahead and tried it, and by copying the header file NSTask.h into my project, I was able to successfully compile the code. Good so far. When I ran the code, though, things didn't go as well. I could create a task, and call its setLaunchPath method, but when I tried to launch it, I got a "launch path not accessible" error. The launch path should be fine, though, since the process I'm trying to launch is a program I copied over a socket, and I'm using the same path I used to write the file as I am for the launch path of the task. Does this suggest that the iOS file system is preventing me from accessing the file to launch it, even though I could access that location to open and write a file? Or is it more likely that I'm making another mistake somewhere?
id x = NSClassFromString(#"NSTask");
if (x) {
NSLog(#"Yes, you can.");
}
else {
NSLog(#"No, you can not.");
}
Basically I am wondering if it is possible to run a console script (.sh) from an iPhone App. The script is written to download a program from a repository that I set up, respring, then after a set time delete the program and respring again, so it needs root privileges, and is interactive in that the user can set how long the program will be kept. I have the bash script written, and it works fine when called from mobile terminal, but is there any way to do this from within a (jailbroken) app (without using mobile terminal / SSH / Bossprefs)? Or is there an overall better way to achieve this?
Thanks
Jasarien is right here it is pretty resticted and as we all know that all apps are sandboxed. But it is not impossible since Objective-C is just build on C you can use
system("ls");
to execute a basic ls command and it works if you look in your gdb output. Altho you can also use popen to get the streams to app to work with the data.
Since you're working with a Jailbroken phone, you're pretty much unrestricted. Whether or not there's anything in the iPhone APIs that allows for script execution is another matter though. Also anything you do use will be unsupported, and is likely to change, stop working or be removed in a software update.
Also, you probably already know this, or don't care, but you won't get past Apple's review process for the App Store if you start running BASH scripts. Interpreted code is forbidden.
I would look up how to do it on OSX, chances are that'll be how it's done on the iPhone, but you probably won't find any iPhone specific documentation about it because it's not allowed on a "normal" iphone (one that is not jailbroken)
something you may consider is using NSTask if you want to get output and error messages from the shell.
Actualy
system('ls /'); gives a better result as system('ls');