自动打包脚本有了就想着打了包就直接通过脚本上传到服务器,让测试直接下载,别来打扰我最好。
但是我们的服务器用的是阿里云存储服务,Python的OSS2模块必须要AccessKeySecret来验证,所以就没有使用外网服务器。mac又自带Apache那就打个内网服务器来实现需求。
调研
iOS系统提供itms-services协议来安装ipa包,命令为:
itms-services://?action=download-manifest&url=***.plist
url是一个plist文件的获取地址,在iOS7.1以后必须用https来获取,否则会提示无法安装应用程序,因为证书无效。
那么,
第一步就是用mac自带的Apache搭建一个支持https协议的服务器;
第二步就是关于这个plist文件的配置;
第三步就是读者通过各种姿势玩这个安装命令了。
Apache配置
使Apache支持https协议的大致流程是:
- 创建一个颁发机构CA
- 用CA为你的内网服务器创建证书
- 开通Apache相应的服务
- 把CA证书导出作为邮件的附件发送至需要自由安装的设备,iOS设备可以通过附件直接安装CA证书,设置信任该证书即可
因为下列命令都必须管理者权限,所以先进入管理者模式
sudo su
1. 创建颁发机构CA
1.1. 生成CA密钥
openssl genrsa -des3 -out ca.key 1024
会要求输入访问密码(最少4位,记住以后会用),可以发现当前文件夹生成了一个ca.key的文件,1024应该是复杂度
1.2. 生成CA证书(创建颁发机构CA)
openssl req -new -x509 -days 365 -key ca.key -out ca.crt
在输入ca.key的访问密码后,会要求输入该证书的信息,因为别人不可能用你的CA,所以乱输也没事啦:
- Country Name (2 letter code) [AU]:CN
- State or Province Name (full name) [Some-State]:Sichuan
- Locality Name (eg, city) []:Chengdu
- Organization Name (eg, company) [Internet Widgits Pty Ltd]:Developer
- Organizational Unit Name (eg, section) []:Eason
- Common Name (e.g. server FQDN or YOUR name) []:EasonLeo(这里和下面创建服务器证书有区别)
- Email Address []:1003004733@qq.com(提臀迎众基)
可以发现当前文件夹生成了一个ca.crt的文件,这个文件可以保留,以后创建各种自签名证书时使用,避免需要设备重复信任(在后面会说到)
2. 创建服务器证书
2.1 生成服务器证书密钥
openssl genrsa -des3 -out server.key 1024
同上,生成了server.key
2.2 获取服务器证书请求文件csr(CertificateSigningRequest)
openssl req -new -key server.key -out server.csr
需要server.key的访问密码,iOS开发者中心请求证书时同样也用了csr文件。
这里会和上面在生成CA证书时一样需要配置证书信息,其他的都一样,但是有个不同的地方
- *** Common Name (e.g. server FQDN or YOUR name) []:*** 192.168.0.250
(这里比较重要,是你的域名(可以通过http-vhosts.conf配置一个超炫的域名哟,虽然没卵用)或IP地址,因为我们是搭建内网服务器,所以你需要先设置一个固定的内网IP,在WIFI-高级-TCP/IP里设置,再在这里填入,否则无法连接)
2.3 获取服务器证书
openssl ca -days 365 -keyfile ca.key -cert ca.crt -in server.csr -out server.crt
这就是从CA颁发证书的命令,但因为这个命令不全所以还有一步
mkdir ./demoCA
mkdir ./demoCA/newcerts
touch ./demoCA/index.txt
touch ./demoCA/serial
echo 01 > ./demoCA/serial
再运行CA颁发证书的命令就会出现你请求证书的详情。
会询问你是否签名该证书,那肯定是 y 啊!
会再次询问你签了的证书是否提交,那肯定是 y 啊!
好了,当前文件夹下生成了server.crt证书就是服务器需要的证书,demoCA文件夹里的可以不用管,应该是一些签名记录之类的文件。
总结:生成证书流程为key -> csr -> crt,即先生成key;再用key生成csr;将csr发送给权威CA,或自建CA获取crt。
3.开通Apache相应服务
** 以下注释大多是猜想,没能找到权威说明 **
编辑/etc/apache2/httpd.conf文件,去掉下面三行前面的#号,即开通服务
LoadModule ssl_module libexec/apache2/mod_ssl.so
// 看mod名字不难理解吧。。。
Include /etc/apache2/extra/httpd-ssl.conf
// 允许配置SSL
Include /etc/apache2/extra/httpd-vhosts.conf
// 允许配置端口信息
编辑/etc/apache2/extra/httpd-ssl.conf文件,去掉下面两行前面的#号
SSLCertificateFile "/etc/apache2/ssl/server.crt"
// 证书存放位置,注意前面生成的server.crt就得存放在这设置的路径
SSLCertificateKeyFile "/etc/apache2/ssl/server.key"
// 同上,证书私钥存放位置
编辑/etc/apache2/extra/httpd-vhosts.conf文件,在文件末尾增加
<VirtualHost *:443>
SSLEngine on
// 打开SSL
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
// 密钥解析(一本正经地胡说八道^_^)
SSLCertificateFile /etc/apache2/server.crt
// 注意路径!
SSLCertificateKeyFile /etc/apache2/server.key
// 注意路径!
ServerName 192.168.0.250
// 和生成证书的域名或IP地址一致哦,就是重点标注的那里
DocumentRoot "/Library/WebServer/Documents"
/* 192.168.0.250的根路径注意只有httpd.conf里的DocumentRoot之
后的节点才有权限访问,比如httpd.conf的DocumentRoot
是"/Library/WebServer/Documents",这里的DocumentRoot
是"/Library/WebServer",那么只有192.168.0.250/Documents/***
这样的路径才有权限访问。
如果这里改成"/Library/WebServerSB",那么你前面做这么多都白做了^_^。
*/
</VirtualHost>
自此运行一下命令
apachectl configtest
看下报什么错,我记得会报一个mod_socache_shmcb的错误,不难发现报的错是这个模块没开通,去httpd-conf取消LoadModule...mod_socache_shmcb.so前面的#号就好,当然可能还有其他错误,因httpd-conf这个配置文件而异,有问题就百度吧~
最后在configtest通过,打印Syntax OK后,重启Apache服务器,操作命令
apachectl start // 开启
apachectl stop // 关闭
apachectl restart // 重启
待自由安装测试包的设备信任证书
通过邮件附件发送证书(CA证书、CA证书、CA证书,三遍)到设备自带的邮件APP上,一般邮件APP绑定了icloud账号的,所以邮件收件人可以填设备的icloud邮箱。当然你也可以在设置里增加邮箱账号,这个比较麻烦,有需要再问吧。
安装证书以后,需要到 通用->关于本机->信任的证书 里去打开该证书的开关,哎,当初忘了这一点,妈的翻来覆去地想就觉得我的理论应该正确了啊,为啥还不能信任我的https协议,在多次安装证书后发现系统在安装确认的时候就说了需要去打开开关。可能系统版本比较低的设备没有这个需要,所以请在安装证书的时候仔细阅读描述!
Plist文件配置
哎呀,直接代码吧
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>items</key>
<array>
<dict>
<key>assets</key>
<array>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>https://192.168.0.250/ios/developer/test.ipa</string>
</dict>
<dict>
<key>kind</key>
<string>display-image</string>
<key>needs-shine</key>
<true/>
<key>url</key>
<string>https://192.168.0.250/ios/developer/icon.png</string>
</dict>
<dict>
<key>kind</key>
<string>full-size-image</string>
<key>needs-shine</key>
<true/>
<key>url</key>
<string>https://192.168.0.250/ios/developer/fullimage.png</string>
</dict>
</array>
<key>metadata</key>
<dict>
<key>bundle-identifier</key>
<string>com.developer.eason</string>
<key>bundle-version</key>
<string>1</string>
<key>kind</key>
<string>software</string>
<key>title</key>
<string>自由安装测试</string>
</dict>
</dict>
</array>
</dict>
</plist>
将Plist文件放在DocumentRoot的某个路径下,比如我的DocumentRoot是"/Library/WebServer/Documents"并且plist文件放在"/Library/WebServer/Documents/ios/developer/下",那么itms-services协议的安装命令就是:
itms-services://?action=download-manifest&url=https://192.168.0.250/ios/developer/mainfest.plist
通过这个命令就可以安装测试包了,比如在产品Debug版本的个人中心里加一个版本更新按钮,事件响应就是
if let url = URL(string: "itms-services://?action=download-manifest&url=https://192.168.0.250/ios/developer/mainfest.plist") {
assert(UIApplication.shared.openURL(url), "what the fuck?!")
}
那么,就酱。
感言
哇,终于还是开始写这些笔记了,虽然累但是有成就感啊!