1.7 后台程序
Android 应用能够在后台创建执行代码的服务,这些服务可能会偷偷下载文件消耗流量,导致扣费。iOS 应用则不能在后台执行代码,只要用户单击 Home 键,前台应用的所有线程就都会被挂起,只有播放音乐、获取实时位置等必须在后台执行的操作才能执行。不过在 iOS 中,也是有后台程序的,这些程序被称为守护程序(daemon)。试想在打开 Safari(浏览器)上网时,突然有电话打进来,这时接听电话的界面就会在前台显示,要是没有后台程序,怎么处理来电呢?只是苹果公司并没有给开发者开放后台程序,只有越狱之后,才能开发后台程序。
iOS 的系统进程 launchd 会在系统启动后检测 /System/Library/LaunchDaemons 和 /Library/LaunchDaemons 这两个目录下的 .plist 文件,.plist 文件描述了守护程序的路径。
下面我们编写一个守护程序进行测试,该程序的名称为 daemonTest,其功能是每隔 5 秒输出一条信息,具体代码如下:
#include <stdio.h>
#include <UIKit/UIKit.h>
int main(){
int i=0;
while(1){
NSLog(@"Daemon test %d", i);
i++;
sleep(5);
}
return 0;
}
编译:
clang -arch armv7 -isysroot $(xcrun --sdk iphoneos -show-sdk-path) -framework Foundation -o daemonTest main.m
签名:
codesign -s - --entitlements ~/ent.plist -f daemonTest
签名需要用到的 ent.plist 文件的内容请参考 2.5.1 节。然后我们编写用于描述 daemonTest 的 .plist 文件,文件名称为 net.exchen.daemonTest.plist,其具体内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" >
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<true/>
<key>Label</key>
<string>net.exchen.daemonTest</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/daemonTest</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>SessionCreate</key>
<true/>
<key>StandardErrorPath</key>
<string>/dev/null</string>
<key>inetdCompatibility</key>
<dict>
<key>Wait</key>
<false/>
</dict>
</dict>
</plist>
将 daemonTest 上传到 /usr/bin 目录,再将 net.exchen.daemonTest.plist 文件上传到 /Library/LaunchDaemons/ 目录,接着设置相应的权限,命令如下:
chown root:wheel /usr/bin/daemonTest
chmod 755 /usr/bin/daemonTest
chown root:wheel /Library/LaunchDaemons/net.exchen.daemonTest.plist
使用 launchctl load
命令启动守护程序:
launchctl load /Library/LaunchDaemons/net.exchen.daemonTest.plist
我们打开控制台查看日志,就可以看到每隔 5 秒会输出一条信息,如图 1-4 所示,并且在锁屏状态下代码也能执行,因此刚刚编写的守护程序是真正的后台程序。
图 1-4 每隔 5 秒输出一条信息
使用 launchctl unload
命令可以停止守护程序的执行:
launchctl unload /Library/LaunchDaemons/net.exchen.daemonTest.plist