简介
iOS
平台发布应用,想绕过AppStore
,最好的方式就是In-House
发布了(由于越狱用户覆盖不全,一般不考虑越狱方式)。
网上搜索In-House
的教程也很多,怎么申请企业证书,怎么对ipa
包进行大包签名我就不再复述,文章最后附了两个链接,不了解的童鞋可以看一看。
如果有做过In-House
部署,应该知道,需要准备一个描述应用信息的*.plist
文件上传到服务器,并且从iOS7
及以后版本,此文件必须部署在HTTPS
服务器上才能正常安装。这一步非常容易出错不能成功部署。
出错原因:
- 签名错误或者打包方式不对。
- 是因为对配置文件不了解,出错了也不知道错在哪里。
- 没有条件部署
HTTPS
服务器
最简单的方式(上传ipa
包到http
服务器,调用一个js
方法)
- 安装页面引入这个
JS
<span class="hljs-tag"><<span class="hljs-title">script</span> <span class="hljs-attribute">src</span>=<span class="hljs-value">"http://iosinstall.sinaapp.com/ios/install.js"</span>></span><span class="hljs-tag"></<span class="hljs-title">script</span>></span>
- 在安装按钮的位置调用
openInstallURL
方法,可以使用任意HTML标签!
<span class="hljs-tag"><<span class="hljs-title">div</span> <span class="hljs-attribute">onclick</span>=<span class="hljs-value">"openInstallURL({
'title' : '我是App标题',
'ipa' : 'http://www.xxx.com/app.ipa',
'version' : '1.0',
'ident' : 'cn.xxx.xxx',
'icon' : ''});"</span>></span>点击安装<span class="hljs-tag"></<span class="hljs-title">div</span>></span>
- 参数说明
参数 说明 备注 title 标题 Safari弹出安装提示时提示的标题 ipa 你猜 ipa包需要你上传到自己的服务器上,然后将可以下载到这个ipa包的URL填写到这里,可以使用 HTTP
协议!version 你再猜 可以随意填写,也可以安装实际填写 ident App唯一标识符 你可以在项目配置的 Bundle Identifier
下看到他icon 安装加载过程中的图标 如果传入空字符串,会有一个默认图标:
Demo
- 对HTML不熟悉的同学可以直接用下面的代码,样式已经写好了,将其保存成
*.html
文件即可
<span class="hljs-tag"><<span class="hljs-title">html</span>></span> <span class="hljs-tag"><<span class="hljs-title">head</span>></span> <span class="hljs-tag"><<span class="hljs-title">meta</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"generator"</span> <span class="hljs-attribute">content</span>=<span class="hljs-value">"HTML Tidy for Mac OS X (vers 31 October 2006 - Apple Inc. build 15.12), see www.w3.org"</span> /></span> <span class="hljs-tag"><<span class="hljs-title">meta</span> <span class="hljs-attribute">charset</span>=<span class="hljs-value">"utf-8"</span> /></span> <span class="hljs-tag"><<span class="hljs-title">meta</span> <span class="hljs-attribute">http-equiv</span>=<span class="hljs-value">"X-UA-Compatible"</span> <span class="hljs-attribute">content</span>=<span class="hljs-value">"IE=edge"</span> /></span> <span class="hljs-tag"><<span class="hljs-title">meta</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"viewport"</span> <span class="hljs-attribute">content</span>=<span class="hljs-value">"width=device-width, initial-scale=1"</span> /></span> <span class="hljs-tag"><<span class="hljs-title">title</span>></span>APP测试<span class="hljs-tag"></<span class="hljs-title">title</span>></span> <span class="hljs-tag"><<span class="hljs-title">link</span> <span class="hljs-attribute">rel</span>=<span class="hljs-value">"stylesheet"</span> <span class="hljs-attribute">href</span>=<span class="hljs-value">"http://iosinstall.sinaapp.com/ios/install.css"</span>></span> <span class="hljs-tag"><<span class="hljs-title">script</span> <span class="hljs-attribute">src</span>=<span class="hljs-value">"http://iosinstall.sinaapp.com/ios/install.js"</span>></span><span class="hljs-tag"></<span class="hljs-title">script</span>></span> <span class="hljs-tag"></<span class="hljs-title">head</span>></span> <span class="hljs-tag"><<span class="hljs-title">body</span>></span> <span class="hljs-tag"><<span class="hljs-title">h5</span> <span class="hljs-attribute">style</span>=<span class="hljs-value">"text-align: center; color: red; padding: 20px;"</span>></span>⚠️注意!以下安装包仅用于测试!<span class="hljs-tag"><<span class="hljs-title">br</span>/></span><span class="hljs-tag"></<span class="hljs-title">h5</span>></span> <span class="hljs-tag"><<span class="hljs-title">install-btn</span> <span class="hljs-attribute">onclick</span>=<span class="hljs-value">"openInstallURL({ 'title' : '我是标题', 'ipa' : 'http://www.xxx.com/ipa/xxxx.ipa', 'version' : '1.0', 'ident' : 'com.xxx.xxx', 'icon' : ''});"</span>></span>点击我安装<span class="hljs-tag"></<span class="hljs-title">install-btn</span>></span> <span class="hljs-tag"></<span class="hljs-title">body</span>></span> <span class="hljs-tag"></<span class="hljs-title">html</span>></span>
如果你想完全自己提供这些,请看下面的内容。
实现原理
我曾经为了解决In-House
部署问题,也走了很多弯路,为了解决HTTPS
的问题,使用私有证书,利用Dropbox
的HTTPS服务,又或是使用Github的HTTPS服务,这些方式都是可行的,但是都有不同程度的麻烦,于是有了今天这个帖子。
实现逻辑:客户端根据自己的软件需求,传参到服务器,服务器动态生成*.plist
,因为iOS
会检测*.plist
的URL,不能带有参数,所以将参数用Base64
加密后加到URL路径中,服务器截取路径中的参数部分解密获得参数。由于路径变化的特殊性,需要配置好服务器的重定向。
这样,就不需要每个新的应用都去配置一次*.plist
文件了!
我现在提供的动态*.plist
运行在新浪云稳定快速,可以放心使用!
js
实现的逻辑:收集参数,将参数加密成Base64字符串,插入到访问URL里面。
<span class="hljs-comment">// http://iosinstall.sinaapp.com/ios/install.js</span> <span class="hljs-keyword">var</span> base64EncodeChars = <span class="hljs-string">"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"</span>; <span class="hljs-keyword">var</span> base64DecodeChars = <span class="hljs-keyword">new</span> Array( -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, <span class="hljs-number">62</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, <span class="hljs-number">63</span>, <span class="hljs-number">52</span>, <span class="hljs-number">53</span>, <span class="hljs-number">54</span>, <span class="hljs-number">55</span>, <span class="hljs-number">56</span>, <span class="hljs-number">57</span>, <span class="hljs-number">58</span>, <span class="hljs-number">59</span>, <span class="hljs-number">60</span>, <span class="hljs-number">61</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>, <span class="hljs-number">8</span>, <span class="hljs-number">9</span>, <span class="hljs-number">10</span>, <span class="hljs-number">11</span>, <span class="hljs-number">12</span>, <span class="hljs-number">13</span>, <span class="hljs-number">14</span>, <span class="hljs-number">15</span>, <span class="hljs-number">16</span>, <span class="hljs-number">17</span>, <span class="hljs-number">18</span>, <span class="hljs-number">19</span>, <span class="hljs-number">20</span>, <span class="hljs-number">21</span>, <span class="hljs-number">22</span>, <span class="hljs-number">23</span>, <span class="hljs-number">24</span>, <span class="hljs-number">25</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, <span class="hljs-number">26</span>, <span class="hljs-number">27</span>, <span class="hljs-number">28</span>, <span class="hljs-number">29</span>, <span class="hljs-number">30</span>, <span class="hljs-number">31</span>, <span class="hljs-number">32</span>, <span class="hljs-number">33</span>, <span class="hljs-number">34</span>, <span class="hljs-number">35</span>, <span class="hljs-number">36</span>, <span class="hljs-number">37</span>, <span class="hljs-number">38</span>, <span class="hljs-number">39</span>, <span class="hljs-number">40</span>, <span class="hljs-number">41</span>, <span class="hljs-number">42</span>, <span class="hljs-number">43</span>, <span class="hljs-number">44</span>, <span class="hljs-number">45</span>, <span class="hljs-number">46</span>, <span class="hljs-number">47</span>, <span class="hljs-number">48</span>, <span class="hljs-number">49</span>, <span class="hljs-number">50</span>, <span class="hljs-number">51</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>); <span class="hljs-comment">// Base64编码的方法</span> <span class="hljs-function">function <span class="hljs-title">base64encode</span><span class="hljs-params">(str)</span> </span>{ <span class="hljs-keyword">var</span> <span class="hljs-keyword">out</span>, i, len; <span class="hljs-keyword">var</span> c1, c2, c3; len = str.length; i = <span class="hljs-number">0</span>; <span class="hljs-keyword">out</span> = <span class="hljs-string">""</span>; <span class="hljs-keyword">while</span>(i < len) { c1 = str.charCodeAt(i++) & <span class="hljs-number">0xff</span>; <span class="hljs-keyword">if</span>(i == len) { <span class="hljs-keyword">out</span> += base64EncodeChars.charAt(c1 >> <span class="hljs-number">2</span>); <span class="hljs-keyword">out</span> += base64EncodeChars.charAt((c1 & <span class="hljs-number">0x3</span>) << <span class="hljs-number">4</span>); <span class="hljs-keyword">out</span> += <span class="hljs-string">"=="</span>; <span class="hljs-keyword">break</span>; } c2 = str.charCodeAt(i++); <span class="hljs-keyword">if</span>(i == len) { <span class="hljs-keyword">out</span> += base64EncodeChars.charAt(c1 >> <span class="hljs-number">2</span>); <span class="hljs-keyword">out</span> += base64EncodeChars.charAt(((c1 & <span class="hljs-number">0x3</span>)<< <span class="hljs-number">4</span>) | ((c2 & <span class="hljs-number">0xF0</span>) >> <span class="hljs-number">4</span>)); <span class="hljs-keyword">out</span> += base64EncodeChars.charAt((c2 & <span class="hljs-number">0xF</span>) << <span class="hljs-number">2</span>); <span class="hljs-keyword">out</span> += <span class="hljs-string">"="</span>; <span class="hljs-keyword">break</span>; } c3 = str.charCodeAt(i++); <span class="hljs-keyword">out</span> += base64EncodeChars.charAt(c1 >> <span class="hljs-number">2</span>); <span class="hljs-keyword">out</span> += base64EncodeChars.charAt(((c1 & <span class="hljs-number">0x3</span>)<< <span class="hljs-number">4</span>) | ((c2 & <span class="hljs-number">0xF0</span>) >> <span class="hljs-number">4</span>)); <span class="hljs-keyword">out</span> += base64EncodeChars.charAt(((c2 & <span class="hljs-number">0xF</span>) << <span class="hljs-number">2</span>) | ((c3 & <span class="hljs-number">0xC0</span>) >><span class="hljs-number">6</span>)); <span class="hljs-keyword">out</span> += base64EncodeChars.charAt(c3 & <span class="hljs-number">0x3F</span>); } <span class="hljs-keyword">return</span> <span class="hljs-keyword">out</span>; } <span class="hljs-comment">/** Demo: var info = { 'title' : '我是标题', // app name 'ipa' : 'http://www.xxx.com/ipa/xxx.ipa', // ipa url 'version' : '1.0', 'ident' : 'cn.xxx.xxx', 'icon' : '' // icon url }; openInstallURL(info); */</span> <span class="hljs-function">function <span class="hljs-title">openInstallURL</span><span class="hljs-params">(info)</span> </span>{ <span class="hljs-keyword">if</span> (info.ident == <span class="hljs-keyword">null</span> || info.ident.length == <span class="hljs-number">0</span>) { info.ident = <span class="hljs-string">'cn.ineva.cn'</span>; } <span class="hljs-keyword">if</span> (info.icon == <span class="hljs-keyword">null</span> || info.icon.length == <span class="hljs-number">0</span>) { info.icon = <span class="hljs-string">'http://sandy.int.ru/wp-content/uploads/auto_save_image/2015/09/023032rvV.png'</span>; } <span class="hljs-keyword">if</span> (info.version == <span class="hljs-keyword">null</span> || info.version.length == <span class="hljs-number">0</span>) { info.version = <span class="hljs-string">'1.0.0'</span>; } <span class="hljs-keyword">var</span> url = info.title + <span class="hljs-string">'@'</span> + info.ipa + <span class="hljs-string">'@'</span> + info.version + <span class="hljs-string">'@'</span> + info.ident + <span class="hljs-string">'@'</span> + info.icon; url = base64encode(encodeURI(url)); url = <span class="hljs-string">'https://iosinstall.sinaapp.com/ios/'</span> + url.substr(<span class="hljs-number">0</span>, url.length-<span class="hljs-number">2</span>) + <span class="hljs-string">'/install.plist'</span>; console.log(url); url = <span class="hljs-string">'itms-services://?action=download-manifest&url='</span> + url; window.self.location = url; }
- 服务器PHP实现:从URL中截获参数,使用参数拼接好
*.plist
文件内容,将拼接好的内容当文件返回。
<span class="php"><span class="hljs-preprocessor"><?php</span> <span class="hljs-comment">//-------------------------------------------</span> <span class="hljs-comment">// 解决 ios8 初期版本安装问题</span> <span class="hljs-variable">$sel</span> = <span class="hljs-keyword">array</span>( <span class="hljs-string">'12A365'</span>, <span class="hljs-string">'12A366'</span>, <span class="hljs-string">'12A402'</span> ); <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">auto_file_name</span><span class="hljs-params">()</span> </span>{ <span class="hljs-keyword">return</span> round(time()/(<span class="hljs-number">60</span>*<span class="hljs-number">10</span>), <span class="hljs-number">0</span>); <span class="hljs-variable">$randNum</span> = rand(<span class="hljs-number">100</span>,<span class="hljs-number">9999</span>); <span class="hljs-variable">$fileName</span> = iconv(<span class="hljs-string">'gb2312'</span>,<span class="hljs-string">'utf-8'</span>, <span class="hljs-variable">$randNum</span>.time()); <span class="hljs-keyword">return</span> <span class="hljs-variable">$fileName</span>; } <span class="hljs-variable">$auto</span> = <span class="hljs-string">''</span>; <span class="hljs-keyword">foreach</span> (<span class="hljs-variable">$sel</span> <span class="hljs-keyword">as</span> <span class="hljs-variable">$s</span>) { <span class="hljs-keyword">if</span> ( strpos(<span class="hljs-variable">$_SERVER</span>[<span class="hljs-string">"HTTP_USER_AGENT"</span>], <span class="hljs-variable">$s</span>) ) { <span class="hljs-variable">$auto</span> = <span class="hljs-string">'.'</span>.auto_file_name(); <span class="hljs-keyword">break</span>; } } <span class="hljs-comment">// 获取参数</span> <span class="hljs-variable">$url</span> = <span class="hljs-string">'http://'</span>.<span class="hljs-variable">$_SERVER</span>[<span class="hljs-string">'SERVER_NAME'</span>].<span class="hljs-string">':'</span>.<span class="hljs-variable">$_SERVER</span>[<span class="hljs-string">"SERVER_PORT"</span>].<span class="hljs-variable">$_SERVER</span>[<span class="hljs-string">"REQUEST_URI"</span>]; <span class="hljs-variable">$tmp</span> = explode(<span class="hljs-string">"/"</span>, <span class="hljs-variable">$url</span>); <span class="hljs-variable">$tmp</span> = <span class="hljs-variable">$tmp</span>[<span class="hljs-number">4</span>]; <span class="hljs-variable">$tmp</span> = <span class="hljs-variable">$tmp</span>.<span class="hljs-string">'=='</span>; <span class="hljs-variable">$tmp</span> = base64_decode(<span class="hljs-variable">$tmp</span>); <span class="hljs-variable">$arr</span> = explode(<span class="hljs-string">"@"</span>, <span class="hljs-variable">$tmp</span> ); <span class="hljs-variable">$title</span> = urldecode( <span class="hljs-variable">$arr</span>[<span class="hljs-number">0</span>] ); <span class="hljs-variable">$url</span> = urldecode( <span class="hljs-variable">$arr</span>[<span class="hljs-number">1</span>] ); <span class="hljs-variable">$version</span> = urldecode( <span class="hljs-variable">$arr</span>[<span class="hljs-number">2</span>] ); <span class="hljs-variable">$ident</span> = urldecode( <span class="hljs-variable">$arr</span>[<span class="hljs-number">3</span>].<span class="hljs-variable">$auto</span> ); <span class="hljs-variable">$icon</span> = urldecode( <span class="hljs-variable">$arr</span>[<span class="hljs-number">4</span>] ); <span class="hljs-variable">$data</span> = <span class="hljs-string">'<?xml version="1.0" encoding="UTF-8"?></span></span> <span class="hljs-tag"><<span class="hljs-title">plist</span> <span class="hljs-attribute">version</span>=<span class="hljs-value">"1.0"</span>></span> <span class="hljs-tag"><<span class="hljs-title">dict</span>></span> <span class="hljs-tag"><<span class="hljs-title">key</span>></span>items<span class="hljs-tag"></<span class="hljs-title">key</span>></span> <span class="hljs-tag"><<span class="hljs-title">array</span>></span> <span class="hljs-tag"><<span class="hljs-title">dict</span>></span> <span class="hljs-tag"><<span class="hljs-title">key</span>></span>assets<span class="hljs-tag"></<span class="hljs-title">key</span>></span> <span class="hljs-tag"><<span class="hljs-title">array</span>></span> <span class="hljs-tag"><<span class="hljs-title">dict</span>></span> <span class="hljs-tag"><<span class="hljs-title">key</span>></span>kind<span class="hljs-tag"></<span class="hljs-title">key</span>></span> <span class="hljs-tag"><<span class="hljs-title">string</span>></span>software-package<span class="hljs-tag"></<span class="hljs-title">string</span>></span> <span class="hljs-tag"><<span class="hljs-title">key</span>></span>url<span class="hljs-tag"></<span class="hljs-title">key</span>></span> <span class="hljs-tag"><<span class="hljs-title">string</span>></span>'.$url.'<span class="hljs-tag"></<span class="hljs-title">string</span>></span> <span class="hljs-tag"></<span class="hljs-title">dict</span>></span> <span class="hljs-tag"><<span class="hljs-title">dict</span>></span> <span class="hljs-tag"><<span class="hljs-title">key</span>></span>kind<span class="hljs-tag"></<span class="hljs-title">key</span>></span> <span class="hljs-tag"><<span class="hljs-title">string</span>></span>display-image<span class="hljs-tag"></<span class="hljs-title">string</span>></span> <span class="hljs-tag"><<span class="hljs-title">key</span>></span>needs-shine<span class="hljs-tag"></<span class="hljs-title">key</span>></span> <span class="hljs-tag"><<span class="hljs-title">true</span>/></span> <span class="hljs-tag"><<span class="hljs-title">key</span>></span>url<span class="hljs-tag"></<span class="hljs-title">key</span>></span> <span class="hljs-tag"><<span class="hljs-title">string</span>></span>'.$icon.'<span class="hljs-tag"></<span class="hljs-title">string</span>></span> <span class="hljs-tag"></<span class="hljs-title">dict</span>></span> <span class="hljs-tag"></<span class="hljs-title">array</span>></span> <span class="hljs-tag"><<span class="hljs-title">key</span>></span>metadata<span class="hljs-tag"></<span class="hljs-title">key</span>></span> <span class="hljs-tag"><<span class="hljs-title">dict</span>></span> <span class="hljs-tag"><<span class="hljs-title">key</span>></span>bundle-identifier<span class="hljs-tag"></<span class="hljs-title">key</span>></span> <span class="hljs-tag"><<span class="hljs-title">string</span>></span>'.$ident.'<span class="hljs-tag"></<span class="hljs-title">string</span>></span> <span class="hljs-tag"><<span class="hljs-title">key</span>></span>bundle-version<span class="hljs-tag"></<span class="hljs-title">key</span>></span> <span class="hljs-tag"><<span class="hljs-title">string</span>></span>'.$version.'<span class="hljs-tag"></<span class="hljs-title">string</span>></span> <span class="hljs-tag"><<span class="hljs-title">key</span>></span>kind<span class="hljs-tag"></<span class="hljs-title">key</span>></span> <span class="hljs-tag"><<span class="hljs-title">string</span>></span>software<span class="hljs-tag"></<span class="hljs-title">string</span>></span> <span class="hljs-tag"><<span class="hljs-title">key</span>></span>title<span class="hljs-tag"></<span class="hljs-title">key</span>></span> <span class="hljs-tag"><<span class="hljs-title">string</span>></span>'.$title.'<span class="hljs-tag"></<span class="hljs-title">string</span>></span> <span class="hljs-tag"></<span class="hljs-title">dict</span>></span> <span class="hljs-tag"></<span class="hljs-title">dict</span>></span> <span class="hljs-tag"></<span class="hljs-title">array</span>></span> <span class="hljs-tag"></<span class="hljs-title">dict</span>></span> <span class="hljs-tag"></<span class="hljs-title">plist</span>></span>'; $file_size = strlen($data); $filename = 'appinstall.plist'; $filename = iconv("UTF-8", "GB2312", $filename); ob_clean(); header("Content-type:application/octet-stream"); header("Server:nginx/1.4.4"); header("Content-type:text/plain"); header("Accept-Ranges:bytes"); header("Accept-Length:".$file_size); header("Content-Disposition: attachment; filename=".$filename); echo $data;