最簡單企業證書部署應用!In-House改進版!免HTTPS!

⚠️由於新浪服務器升級,限制目錄和文件名的長度,因此更換實現方式

簡介

iOS平臺發佈應用,想繞過AppStore,最好的方式就是In-House發佈了(因爲越獄用戶覆蓋不全,通常不考慮越獄方式)。
網上搜索In-House的教程也不少,怎麼申請企業證書,怎麼對ipa包進行大包簽名我就再也不復述,文章最後附了兩個連接,不瞭解的童鞋能夠看一看。php

若是有作過In-House部署,應該知道,須要準備一個描述應用信息的*.plist文件上傳到服務器,而且從iOS7及之後版本,此文件必須部署在HTTPS服務器上才能正常安裝。這一步很是容易出錯不能成功部署。css

出錯緣由:

  • 簽名錯誤或者打包方式不對。html

  • 是由於對配置文件不瞭解,出錯了也不知道錯在哪裏。ios

  • 沒有條件部署HTTPS服務器nginx

最簡單的方式(上傳ipa包到http服務器,調用一個js方法)

  • 安裝頁面引入這個JSgit

<script src="http://iosinstall.sinaapp.com/plist/ios-install.js"></script>
  • 在安裝按鈕的位置調用openInstallURL方法,可使用任意HTML標籤!github

<div onclick="openInstallURL({
    'title'   : '我是App標題',
    'ipa'     : 'http://www.xxx.com/app.ipa', 
    'version' : '1.0',
    'ident'   : 'cn.xxx.xxx', 
    'icon'    : ''});">點擊安裝</div>
  • 參數說明json

參數 說明 備註
title 標題 Safari彈出安裝提示時提示的標題
ipa 你猜 ipa包須要你上傳到本身的服務器上,而後將能夠下載到這個ipa包的URL填寫到這裏,可使用HTTP協議!
version 你再猜 ⚠️iOS9之後,必須跟ipa包上的版本號對應,不然安裝到最後會提示失敗
ident App惟一標識符 你能夠在項目配置的Bundle Identifier下看到他
icon 安裝加載過程當中的圖標 若是傳入空字符串,會有一個默認圖標:

Demo

  • 對HTML不熟悉的同窗能夠直接用下面的代碼,樣式已經寫好了,將其保存成*.html文件便可服務器

<html>
<head>
  <meta name="generator" content="HTML Tidy for Mac OS X (vers 31 October 2006 - Apple Inc. build 15.12), see www.w3.org" />
  <meta charset="utf-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>APP測試</title>
  <link rel="stylesheet" href="http://iosinstall.sinaapp.com/plist/ios-install.css">
  <script src="http://iosinstall.sinaapp.com/plist/ios-install.js"></script>
</head>
<body>
  <h5 style="text-align: center; color: red; padding: 20px;">⚠️注意!如下安裝包僅用於測試!<br/></h5>
  <install-btn onclick="openInstallURL({
    'title'     : '我是標題', 
      'ipa'     : 'http://www.xxx.com/ipa/xxxx.ipa', 
      'version'    : '1.0',
      'ident'   : 'com.xxx.xxx', 
      'icon'    : ''});">點擊我安裝</install-btn>
</body>
</html>

若是你想徹底本身提供這些,請看下面的內容。

實現原理

我曾經爲了解決In-House部署問題,也走了不少彎路,爲了解決HTTPS的問題,使用私有證書,利用Dropbox的HTTPS服務,又或是使用Github的HTTPS服務,這些方式都是可行的,可是都有不一樣程度的麻煩,因而有了今天這個帖子。app

實現邏輯:客戶端根據本身的軟件需求,傳參到服務器,服務器動態生成*.plist,由於iOS會檢測*.plist的URL,不能帶有參數,因此將參數用Base64加密後加到URL路徑中,服務器截取路徑中的參數部分解密得到參數。因爲路徑變化的特殊性,須要配置好服務器的重定向。
這樣,就不須要每一個新的應用都去配置一次*.plist文件了!
我如今提供的動態*.plist運行在新浪雲穩定快速,能夠放心使用!

  • js實現的邏輯:收集參數,將參數加密成Base64字符串,插入到訪問URL裏面。

// http://iosinstall.sinaapp.com/plist/ios-install.js
var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var base64DecodeChars = new Array(
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
    -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
    -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1);
    
// Base64編碼的方法
function base64encode(str) {
    var out, i, len;
    var c1, c2, c3;
    len = str.length;
    i = 0;
    out = "";
    while(i < len) {
        c1 = str.charCodeAt(i++) & 0xff;
        if(i == len) {
            out += base64EncodeChars.charAt(c1 >> 2);
            out += base64EncodeChars.charAt((c1 & 0x3) << 4);
            out += "==";
            break;
        }
        c2 = str.charCodeAt(i++);
        if(i == len) {
            out += base64EncodeChars.charAt(c1 >> 2);
            out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
            out += base64EncodeChars.charAt((c2 & 0xF) << 2);
            out += "=";
            break;
        }
        c3 = str.charCodeAt(i++);
        out += base64EncodeChars.charAt(c1 >> 2);
        out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
        out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6));
        out += base64EncodeChars.charAt(c3 & 0x3F);
    }
    return out;
}

// 計算hash值
var I64BIT_TABLE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-'.split('');
function hash(input){
 var hash = 5381;
 var i = input.length - 1;
  
 if(typeof input == 'string'){
  for (; i > -1; i--)
   hash += (hash << 5) + input.charCodeAt(i);
 }
 else{
  for (; i > -1; i--)
   hash += (hash << 5) + input[i];
 }
 var value = hash & 0x7FFFFFFF;
  
 var retValue = '';
 do{
  retValue += I64BIT_TABLE[value & 0x3F];
 }
 while(value >>= 6);
  
 return retValue;
}

/**
  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);
 */
function openInstallURL(info) {
    if (info.ident == null || info.ident.length == 0) {
        info.ident = 'cn.ineva.cn';
    }
    if (info.icon == null || info.icon.length == 0) {
        info.icon = 'http://iosinstall.sinaapp.com/plist/ios-install.png';
    }
    if (info.version == null || info.version.length == 0) {
        info.version = '1.0.0';
    }
    
    var json = JSON.stringify(info)
    var base64String = base64encode(encodeURI(json)).replace(/\=/g, "");
    var fileName = hash(base64String)
    var s = 128;
    var count = Math.ceil( base64String.length / s);
    var path = "";
    // 由於新浪對連接文件名和目錄的長度有限制,json數據,使用`/`分隔
    for (var i = 0; i < count; i++) {
        var l = s;
        if (i == count - 1) {
            l = base64String.length - i * s;
        }
        path += "/" + base64String.substr( i * s, l);
    }
    var url = 'https://iosinstall.sinaapp.com/plist' + path + "/" + fileName + ".plist";
    window.self.location = 'itms-services://?action=download-manifest&url=' + url;
}
  • 服務器PHP實現:從URL中截獲參數,使用參數拼接好*.plist文件內容,將拼接好的內容當文件返回。

<?php
    
    $pathItems = explode('/', $_SERVER["REQUEST_URI"]);
    
    if ( count($pathItems) < 4 ) {
        return;
    }

    $base64Data = "";
    $fileName = "ios-install.plist";
    for ( $i = 2; $i < count($pathItems); $i++ )
    {
        if ( $i == count($pathItems) - 1 ) {
            $fileName = $pathItems[$i];
        } else {
            $base64Data .= $pathItems[$i];
        }
    }
    
    $jsonString = urldecode(base64_decode($base64Data));
    
    $obj = json_decode($jsonString);
    
    $ipa = $obj->ipa;
    $icon = $obj->icon;
    $ident = $obj->ident;
    $version = $obj->version;
    $title = $obj->title;

$data =
'<?xml version="1.0" encoding="UTF-8"?>
<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>'.$ipa.'</string>
</dict>
<dict>
<key>kind</key>
<string>display-image</string>
<key>needs-shine</key>
<true/>
<key>url</key>
<string>'.$icon.'</string>
</dict>
</array>
<key>metadata</key>
<dict>
<key>bundle-identifier</key>
<string>'.$ident.'</string>
<key>bundle-version</key>
<string>'.$version.'</string>
<key>kind</key>
<string>software</string>
<key>title</key>
<string>'.$title.'</string>
</dict>
</dict>
</array>
</dict>
</plist>';
    
    $file_size = strlen($data);
    
    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;

其餘方式發佈(適合開源項目)

我開發的一個看韓國漫畫的項目,使用手機上的Safari打開連接就能夠安裝:http://qzs21.github.io/iComic/
有興趣的話能夠看看這個項目,代碼和安裝包發佈部署都是使用Github(master分支下面是項目代碼,gh-pages分支就是安裝頁面的代碼): https://github.com/qzs21/iComic

相關推薦

很是詳盡的In-House部署教程:http://blog.csdn.net/yangxt/article/details/7998762
利用GithubHTTPS服務部署:http://my.oschina.net/qixiaobo025/blog/321050

相關文章
相關標籤/搜索