By Werner Ruotsalainen on Fri, 07/08/2011
I've played a bit more with creating Cydia packages. I've found out the following:
If you have problems installing Fink...
If you (just like me, see THIS) have problems compiling Fink for OS X 10.6, use THIS executable (linked from THIS tutorial). It works flawlessly. Remember to make it executable: „chmod a+x dpkg-deb-fat”, of course. I've also found out that it's 'MD5' that comes with OS X, not MD5Sum. Use MD5 if you haven't managed to install Fink. This all means you don't need to struggle with trying to install Fink on OS X at all to create DEB files – all you'll need is dpkg-deb-fat accessible directly for download and MD5 already built-in.
(Root) install/uninstall-time scripting in Cydia (DEB files)
Right at the beginning, I told you about the need for the root password to be „alpine” in order to make the system directories (property list files) writable so that my camera enhancer apps can update them. I've read a bit more into the subject and found out in THIS tutorial that you can give the Debian package system a script that can include commands. (This info isn't present in the original tutorial I've recommended; this is why I haven't used it right at the beginning.) These files, preinst, postinst and prerm, postrm let for executing shell commands before and after the actual .deb install / uninstall, respectively. They are run as „root”, which means it's there that you can issue the commands I've previously done using the system() call from inside my code with the „alpine” password wired-in. As the scripts run as root, you don't need to force the user to have the root password in its unmodified („alpine”) form.
Note that the tutorial contains a mistake: prerm is executed before removing the app and not before installing it, as is also explained HERE. Before-installation scripts should be named, as has already been explained, preinst instead.
BTW, speaking of the previously-mentioned tutorial, it'll become very handy for you if you try to create your DEB files on a desktop computer where, for some reason, you in no way can run pkg-deb to create the DEB file from your resources (control file + the app itself and the two optional pre/post inst/rm files) – for example, on Windows desktops.
Now, let's take a look at how the new code works, making use the new information on these script files. I make use of both an installation- and a uninstallation-time scripting support. In the former, I run the code that, so far, has been executed by the app delegate (with wired-in root password). The pre/postinst (that is, the script that is executed right before/after the DEB file has been installed; there's no difference in which of the two you use) file looks the following:
chmod o+w /System/Library/Frameworks/AVFoundation.framework/N90/AVCaptureSession.plist
chmod o+w /System/Library/Frameworks/AVFoundation.framework/N90/
chmod o+w /System/Library/PrivateFrameworks/Celestial.framework/N90/AVCapture.plist
chmod o+w /System/Library/PrivateFrameworks/Celestial.framework/N90/
And the pre/postrm (the script that is executed right before/after the DEB file has been removed by Cydia) file is as follows:
chmod o-w /System/Library/Frameworks/AVFoundation.framework/N90/AVCaptureSession.plist
chmod o-w /System/Library/Frameworks/AVFoundation.framework/N90/
chmod o-w /System/Library/PrivateFrameworks/Celestial.framework/N90/AVCapture.plist
chmod o-w /System/Library/PrivateFrameworks/Celestial.framework/N90/
if [ -d /var/mobile/Library/ip4-VideoCameraPlus ]; then
rm -r /var/mobile/Library/ip4-VideoCameraPlus
In the uninstaller, I set back the original permissions of the system files and get rid of all my document files, including the directory itself, by a conditional(!) rm -r. (Remember: unlike AppStore / Xcode apps' Documents, the Cydia directory doesn't get automatically cleaned up / removed when you uninstall your Cydia / DEB apps!)
Why the conditional rm -r, you may ask. Well, it's easy: if you try to delete a non-existing directory (or files) from a Debian package script like these, you get a nasty error:
(screenshot from the 3G S version)
Attempting to delete an empty directory / non-existing files is all too easy in our case. As I've already pointed out, it's not the install-time scripts that create the docs dir, but the application itself when it's run for the first time. However, if the user decides not to keep the app and deletes it right after the installation, the uninstall script will report the above error.
Now, if this happens in the prerm file (that is, the one executed before removing the package itself), you're practically shot – it's only by some hacking that you can get rid of the error.
However, if this happens in postrm, when you return Cydia, it offers you a complete cleanup:
This only happens with the postrm script, never with prerm. To fix uninstallable apps, don't even try do anything (e.g., to removing the repository) inside Cydia to get rid of the package. You'll need to go to /var/lib/dpkg/info and manually remove com.winmobiletech.ip4videocameraenhancer.prerm, that is, the script with the wrong content, from there. After that, upgrade / removal will work.
Also note that other nasty errors can also creep in from other sources; for example, if you edit the file in a Windows editor, which adds a \n to the \r; this results in a syntax error right in the first row (and all the other rows too).
Of course, you'll always want to avoid situations like this and try to handle all possible situations (for example, the user not running the app at all) and using conditionals with operations (like the “rm” above) that, otherwise, would make it impossible to (un)install an app. And keep in mind: if you have the slightest doubt any command in your cleanup script may fail, always make it post-removal so that users will still be able to get rid of the app and won't need to mess around in /var/lib/dpkg/info/.
Using these files means I could finally get rid of all fragile (again, what if the user changes his/her password?) system() calls in the app delegate.
Note that I could have created the /var/mobile/Library/ip4-VideoCameraPlus directory from the installation-time script too in order to remove programmatic directory creation in the app delegate. However, as “/var/mobile” is owned by the user Cydia apps run as (“mobile”), creating / modifying directories under /var/mobile doesn't require root privileges (as opposed to setting the permissions under /System/Library/Frameworks/AVFoundation.framework/ or /System/Library/PrivateFrameworks/Celestial.framework/), so, I didn't find it necessary to move that code to the scripting side (as an additional “mkdir /var/mobile/Library/ip4-VideoCameraPlus” command). In addition, by doing this, I would have lost the ability to allow for installing additional hacks on top of my application's own ones without having to completely reinstall my app in between. Should I have gone the way of script-based directory creation, I couldn't consider the system configuration files as ones to backup after restarting the app as there would be no actual code to re-create the directory (remember, the directory is removed in FirstViewController's restroreOrigConfig). The latter would also mean completely losing the ability to back up / restore advanced (user) configurations (see the plist used by Advanced view).
By the way, you may ask how come iFile is able to change the permissions (see my dedicated tutorial HERE) of any system file even when the root password has been changed from “alpine” to something else while, as I've just stated, traditional (most) Cydia apps run as user “mobile” and can't do the same (that is, change permissions of many files). The sole reason for this is that iFile is one of the very few Cydia apps that run as “root” and not as “mobile”; hence the ability to change any permissions in any password configuration.
Making Cydia / hack development much faster
Would you like to install DEB files without having to upload them to a Cydia repository - a time-consuming process with all the hassles of filling in the actual size/MD5 in the Package file and the like? It's actually very easy.
a.) if you don't mind having to restart the entire phone, just copy the DEB file to /var/root/Media/Cydia/AutoInstall with any iOS file system accessor tool on the desktop. After this, restart the phone – during reboot, Cydia will install the app, also running the pre/postinstall scripts. Note that if the directory doesn't exist, create it by hand (Cydia/AutoInstall), making sure you pay attention to the capitalization. A step-by-step file transfer tutorial with Fugu is HERE – note that it's much more complicated than simply using tools (see below) like i-FunBox or iFile – or, for that matter, any tool that works over USB and doesn't require OpenSSH and all its disadvantages (e.g., having to look up the IP address of the device).
Note that some iDevice accessor apps even have dedicated support to copy DEB files to /var/root/Media/Cydia/AutoInstall; for example, the Windows-only i-FunBox (see “Cydia App Install” in the left, Folder View pane - click it and just drop the DEB file(s) in the right pane).
If you don't want to wait for the device to reboot, another choice is using iFile right on the device. Just copy the DEB file anywhere on the phone, navigate to the file in iFile, tap the DEB file and select “Installer” from the menu. Note that iFile won't “respring” your device, which is needed for the icon of the app to become visible. (It's similar to completely restarting your phone, but orders of magnitude faster.) To do this, you have several choices. If you don't need the functionality of SBSettings, BossPrefs or don't like the way it's invoked (or use an iOS version still completely incompatible with SBSettings; for example, the current [as of 07/07/2011] iOS5 beta versions), you may just download “Respring” (current version 4.0) from Cydia and use it to quickly restart the device. It'll put a “Respring” icon on your Springboard; just tap it to quickly refresh the icons.
Finally, if you prefer doing everything manually, without the help of any external apps (except for respringing), after copying the DEB file anywhere on your iPhone just issue the dpkg -i filename.deb command from either a desktop-based SSH client (if you have one and also installed OpenSSH on the iPhone) or MobileTerminal on the phone (see THIS article for more info on acquiring a recent version). Note that, no matter what some people state (see e.g. THIS), issuing “killall SpringBoard” won't result in the icon being shown (as is also emphasized for example HERE, in BigBoss' official tutorial on code signing for Cydia).
Again, what's the point in all this? When you develop for Cydia, there can be cases when simply deploying from under Xcode won't be sufficient. An example is testing and fine-tuning before/after Cydia / DEB scripts (which, of course, can't be done from inside an Xcode project) or just accessing resources that an app deployed by Xcode is just unable to access, no matter what you do, what permissions you grant to these files / their directories. Examples of these are /var/wireless/Library/CallHistory/call_history.db (call history), /var/mobile/Library/Calendar/Calendar.sqlitedb (Calendar database; you may need this under iOS versions prior to 4.0 as, starting with 4.0, EvenKit allows access to Calendar records), /var/mobile/Library/SMS/SMS.db (SMS messages). Of course, it's always the fastest to do as much as possible with Xcode and only create / use DEB files if you develop/test functionality not accessible from an Xcode project.
Finally, note how much easier it is to deploy and install DEB files this way. Should you stick with the Cydia way, it'd require a lot more work to deploy your stuff on your iPhone than via a simple file copier + iFile + Respring. Just to recap:
Common you'll always need to do (assuming you've already built up the source directory with the native ARM app bundle in Applications and at least the control file in DEBIAN; here, I assume that the app name's ip4vcamplus):
dpkg-deb[-fat] -b ip4vcamplus
… to create the DEB file (generally, if you leave open the terminal window, just an Up to redisplay the previous command and Enter).
If you stick with installing the standard way, that is, via Cydia, after this you'll also need to do the following:
1, md5 ip4vcamplus.deb (to get the MD5 needed for Packages)
2, Enter the size and the md5 sum into the Packages file
3, recompress it with gzip (gzip -f Packages). Note that if you don't want to use gzip and don't mind working from a Windows window, Total Commander can directly edit local (not remote!) gzip files. Otherwise, you can use “gzip -d Packages.gz” to decompress the compressed Packages.gz file to get the original Packages file so that you can edit it.
4, upload both Packages.gz and the .deb file to your private Cydia repo, overwriting the old files.
5, [re]install the app from Cydia.
With iFile, you don't need to any of the previous steps: just drop the output DEB of dpkg-deb[-fat] and tap on it from inside iFile, select Installer and, finally, respring. A LOT less time, taps and inconvenience!
Finally, again, don't forget that you don't even need iFile if you have a (remote) terminal; then, just use dpkg -i filename.deb followed by respringing. (On the desktop, keep the terminal open or, on the iOS terminal, assign the command to a shortcut to be able to quickly repeat it via the left icon displayed when starting the app – or, just assign for example “swipe up” to “Up key” to quickly issue the previous command(s) in the history again. They'll be remembered via Terminal restarts.)
Signing with ldid
Finally, if you plan to submit your app to an “official” Cydia repo, you'll want to follow THIS tutorial. I haven't followed it myself when creating the current packages as I'm a paying Apple developer and my Cydia apps work just fine on others' devices without any special signing magic.
Hope you find this information helpful!
Yet another thing...
I've uploaded the new iPhone 4 / 3GS-specific app version (1.5 / 1.7, respectively) in Cydia. The iP3GS / iP4 sources are HERE and HERE, respectively. The pre/post install/uninstall files are easily extractable from the DEB files (they're HERE) – just download the DEB files to your desktop, rename them to <name>.tar and issue the tar xfv <name>.tar command. Then, all you'll need is looking into the control directory in the control.tar.gz file created when un-taring the archive. It'll have all the original files originally present in the DEBIAN subdirectory.
The major change is, as you may have already guessed based on the article so far, that I've moved permission setting in an install-time script (and the docs directory removal into uninstall-time one). Now, it doesn't require the root password to be “alpine” as these scripts are run as “root”, not as “mobile” (the restricted user Cydia apps are run). With uninstall-time directory deletion, I've also eliminated the need to manually tap the “Restore Original Configuration” button before uninstallation to remove the docs directory.