iOS AD-HOC 自己打包分发 内部测试

下载页面

<!DOCTYPE html>  
<html>  
<head>  
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
  <title>游戏Demo</title>  
</head>  
<body>  
<h1>1. iOS安装 <a href="https://xxxx/iOS/xxx_public.crt">证书</a><br/>(如果已经有https站点,这步跳过,如果之前尚未安装过此证书,请先安装证书)</h1>
<br/>  
<h1>2. iOS安装 <a href="itms-services://?action=download-manifest&url=https://xxxx/iOS/manifest.plist">游戏包</a></h1>
<br/>
<h1>3. Android安装 <a href="https://xxxx/ipa/thirtysix.apk">apk安装包</a></h1>  
</body>
</html>  

重点 manifest.plist 格式 和制作

<?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><![CDATA[https://xxxx/iOS/ProductName.ipa]]></string>
        </dict>
        <dict>
          <key>kind</key>
          <string>display-image</string>
          <key>needs-shine</key>
          <integer>0</integer>
          <key>url</key>
          <string><![CDATA[https://xxxx/iOS/Icon-Store-1024.png]]></string>
        </dict>
        <dict>
          <key>kind</key>
          <string>full-size-image</string>
          <key>needs-shine</key>
          <true/>
          <key>url</key>
          <string><![CDATA[https://xxxx/iOS/Icon-Store-1024.png]]></string>
        </dict>
      </array>
      <key>metadata</key>
      <dict>
        <key>bundle-identifier</key>
        <string>com.xxx.xxx</string>
        <key>bundle-version</key>
        <string><![CDATA[1.204.5]]></string>
        <key>kind</key>
        <string>software</string>
        <key>title</key>
        <string><![CDATA[app名字]]></string>
      </dict>
    </dict>
  </array>
</dict>
</plist>

把对应的 ipa 上传到文件服务器(注意需要时https支持下载)即可.

对了,下面给出 命令行 编译 ipa 需要的 plist 配置文件
ad-hoc.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>method</key>
    <string>ad-hoc</string>
    <key>teamID</key>
    <string>xxxxxx</string>
    <key>uploadBitcode</key>
    <true/>
    <key>uploadSymbols</key>
    <true/>
    <key>manifest</key>
    <dict>
        <key>appURL</key>
        <string>https://xxxx/iOS/ProductName.ipa</string>
        <key>displayImageURL</key>
        <string>https://xxxx/iOS/Icon-Store-1024.png</string>
        <key>fullSizeImageURL</key>
        <string>https://xxxx/iOS/Icon-Store-1024.png</string>
        <key>assetPackManifestURL</key>
        <string>https://xxxx/iOS/manifest.plist</string>
    </dict>
</dict>
</plist>

app-store.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>method</key>
    <string>app-store</string>
    <key>teamID</key>
    <string>XXXX</string>
    <key>uploadBitcode</key>
    <true/>
    <key>uploadSymbols</key>
    <true/>
</dict>
</plist>

编译命令

'/usr/bin/xcodebuild -exportArchive -archivePath %s -exportOptionsPlist %s -exportPath %s -allowProvisioningUpdates -allowProvisioningDeviceRegistration' % (archivePath,exportOptionsPlist,exportPath)

完整的编译脚本 autobuild.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from optparse import OptionParser
import subprocess
import requests
import datetime
import os
import myemail
import re

curPath=os.path.split(os.path.realpath(__file__))[0]

messagetxt="本次上传包含:"

def cleanBuildDir(workspaceName,configuration,scheme):
    buildCmd = '/usr/bin/xcodebuild -quiet clean -workspace %s -configuration %s -scheme %s' % (workspaceName,configuration,scheme)
    if workspaceName is None :
        buildCmd = '/usr/bin/xcodebuild -quiet clean -configuration %s -scheme %s' % (configuration,scheme)
    print(buildCmd)
    process = subprocess.Popen(buildCmd, shell = True)
    process.wait()

def uploadIpaToFir(ipaPath ,firkey,changelog):
    buildCmd = '/usr/local/bin/fir login %s && /usr/local/bin/fir publish %s -c %s' % (firkey,ipaPath,changelog)
    print(buildCmd)
    process = subprocess.Popen(buildCmd, shell = True)
    process.wait()

def buildWorkspace(workspaceName, scheme, configuration, archivePath):
    buildCmd = '/usr/bin/xcodebuild -quiet archive -workspace %s -scheme %s -configuration %s -archivePath %s' % (workspaceName,scheme,configuration,archivePath)
    if workspaceName is None :
        buildCmd = '/usr/bin/xcodebuild -quiet archive -scheme %s -configuration %s -archivePath %s' % (scheme,configuration,archivePath)
    print(buildCmd)
    process = subprocess.Popen(buildCmd, shell = True)
    process.wait()

def exportipa(archivePath, exportPath, exportOptionsPlist):
    buildCmd = '/usr/bin/xcodebuild -exportArchive -archivePath %s -exportOptionsPlist %s -exportPath %s -allowProvisioningUpdates -allowProvisioningDeviceRegistration' % (archivePath,exportOptionsPlist,exportPath)
    print(buildCmd)
    process = subprocess.Popen(buildCmd, shell=True)
    '''out_value=process.communicate()
    regex = re.compile("Errors=\{")
    if regex.match("".join(out_value)) :
        logfile = writelog(out_value)
        print("build error please log:%s"%(logfile))
        exit()'''
    process.wait()

def uploadIpaToAppStore(ipaPath_appstore, appleID, applepassword):
    altoolPath="xcrun altool"
    #buildCmd = '%s --validate-app -f %s -u %s -p %s -t ios --output-format xml' % (altoolPath, ipaPath_appstore, appleID, applepassword)
    #process = subprocess.Popen(buildCmd, shell = True)
    #process.wait()
    buildCmd = '%s --upload-app -f %s --apiIssuer %s --apiKey %s -t ios --output-format xml' % (altoolPath, ipaPath_appstore, appleID, applepassword)
    print(buildCmd)
    process = subprocess.Popen(buildCmd, shell = True)
    process.wait()
    
def writelog(logstr):
    timenow = datetime.datetime.now()
    timestr = datetime.datetime.strftime(timenow,'%H-%M-%S')
    datestr = datetime.datetime.strftime(timenow,'%Y-%m-%d')
    dirstr = '%s_%s' % (datestr,timestr)
    logfile = '%s/log/%s.txt'%(curPath,dirstr)
    file_object=open(logfile, 'w+')
    file_object.write(logstr)
    file_object.close()
    return logfile

    
def xcbuild(options):
    global messagetxt
    if options.scheme is not None:
        if options.needCompile:
            cleanBuildDir(options.workspace,options.configuration,options.scheme)
            buildWorkspace(options.workspace, options.scheme, options.configuration, options.archivePath)
            if options.backUpArchive is not None:
                buildCmd = 'cp -a %s %s' % (options.archivePath,options.backUpArchive)
                print(buildCmd)
                process = subprocess.Popen(buildCmd, shell = True)
                process.wait()
                
        if options.export == 1:
            exportipa(options.archivePath,options.exportPath_adhoc,options.exportOptionsPlist_adhoc)
            messagetxt = messagetxt + "导出test的ipa"
        elif options.export == 2:
            exportipa(options.archivePath,options.exportPath_appstore,options.exportOptionsPlist_appstore)
            messagetxt = messagetxt + "导出AppStore的ipa"
        elif options.export == 3:
            exportipa(options.archivePath,options.exportPath_adhoc,options.exportOptionsPlist_adhoc)
            exportipa(options.archivePath,options.exportPath_appstore,options.exportOptionsPlist_appstore)
            messagetxt = messagetxt + "导出test、AppStore的ipa"

        if options.upload == 1:
            print ("build and upload test")
            uploadIpaToFir(options.ipaPath_adhoc, options.firkey,options.changelog)
            messagetxt = messagetxt + "上传测试版本"
            #myemail.send_mail(options.scheme, "%s:%s"%(messagetxt,options.note), ",http://hp3h1.hidog.net/shareapp/test.php")
        elif options.upload == 2:
            print ("build and upload appstore")
            uploadIpaToAppStore(options.ipaPath_appstore,options.appleid, options.applepassword)
            messagetxt = messagetxt + "上传AppStore发布版本"
            #myemail.send_mail(options.scheme, "%s:%s"%(messagetxt,options.note), "")
        elif options.upload == 3:
            print ("build and upload appstore & test")
            uploadIpaToFir(options.ipaPath_adhoc, options.firkey,options.changelog)
            messagetxt = messagetxt + "上传测试版本"
            uploadIpaToAppStore(options.ipaPath_appstore,options.appleid, options.applepassword)
            messagetxt = messagetxt + "、AppStore发布版本,备注:%s,http://hp3h1.hidog.net/shareapp/test.php" % options.note
            #myemail.send_mail(options.scheme, messagetxt, "")
        

def main():
    parser = OptionParser()
    parser.add_option("-s", "--scheme",         type="string",  help="Build the scheme specified by schemename. Required if building a workspace.", metavar="schemename")
    parser.add_option("-e", "--export",         type="int",     help="specify export filename",                                                     metavar="output_filename")
    parser.add_option("-u", "--upload",         type="int",     help="upload filename",                                                             metavar="upload_filename")
    parser.add_option("-n", "--note",           type="string",  help="specify publish note",                                                        metavar="publish note")
    parser.add_option("-a", "--archivePath",    type="string",  help="archivePath",                                                                 metavar="archivePath")
    parser.add_option("-t", "--team",           type="int",     help="whichTeam",                                                                   metavar="whichTeam")
    parser.add_option("-w", "--workspace",      type="string",  help="whichWorkspace",                                                              metavar="whichWorkspace")
    parser.add_option("-c", "--changelog",      type="string",  help="changelog",                                                                   metavar="changelog")
    parser.add_option("-d", "--debug",          type="string",  help="debug",                                                                       metavar="debug mode")
    parser.add_option("-b", "--backUpArchive",  type="string",  help="backUpArchive",                                                               metavar="backUpArchive")
    parser.add_option("-r", "--upUser",         type="string",  help="upUser",                                                                      metavar="upUser")
    parser.add_option("-p", "--upPass",         type="string",  help="upPass",                                                                      metavar="upPass")
    parser.add_option("-o", "--ipaPath",        type="string",  help="ipaPath",                                                                     metavar="ipaPath")

    (options, args) = parser.parse_args()

    timenow = datetime.datetime.now()
    datestr = datetime.datetime.strftime(timenow,'%Y-%m-%d')
    timestr = datetime.datetime.strftime(timenow,'%H-%M-%S')
    #datestr = '2019-10-15'
    #timestr = '11-06-59'
    dirstr = '%s/%s_%s' % (datestr,options.scheme,timestr)

    #options.home = os.path.expanduser('~')
    options.home = curPath
    options.ipaPath_adhoc = '%s/../ipa_test/%s/%s.ipa' % (options.home,dirstr,options.scheme)
    options.ipaPath_appstore = '%s/../ipa_release/%s/%s.ipa' % (options.home,dirstr,options.scheme)
    options.exportPath_adhoc = '%s/../ipa_test/%s' % (options.home,dirstr)
    options.exportPath_appstore = '%s/../ipa_release/%s' % (options.home,dirstr)

    if options.ipaPath is not None:
        options.ipaPath_adhoc = '%s/%s/%s.ipa' % (options.ipaPath,dirstr,options.scheme)
        options.ipaPath_appstore = '%s/%s/%s.ipa' % (options.ipaPath,dirstr,options.scheme)
        print("ipaPath "+options.ipaPath_appstore)
        
    if options.team is None:
        options.exportOptionsPlist_adhoc = '%s/packcfghz/ad-hoc.plist' % (options.home)
        options.exportOptionsPlist_appstore = '%s/packcfghz/app-store.plist' % (options.home)
        options.appleid=options.upUser
        options.applepassword=options.upPass
    
    if options.archivePath is None :
        options.archivePath = "%s/Library/Developer/Xcode/Archives/%s/%s.xcarchive" % (os.path.expanduser('~'),datestr,dirstr)
        options.needCompile=True
    else:
        options.needCompile=False

    if options.debug is None or options.debug == "false" :
        options.configuration = "Release"
    else:
        options.configuration = "Debug"
    
    if options.changelog is None:
        options.changelog=""

    options.firkey = "xxxxxxxx"
    
    if options.export is None:
        options.export = 0
    if options.upload is None:
        options.upload = 0
    if options.note is None:
        options.note = ""

    print ("options: %s, args: %s" % (options, args))

    if options.scheme is not None:
        xcbuild(options)

if __name__ == '__main__':
    main()

使用示例,可以结合 Jenkins PipeLine 来使用

/usr/local/bin/python3 ~/Desktop/desk/BuildScript/autobuild.py \
            -s Proj-mobile \
            -d $debug \
            -e $IOS_UPLOAD_TYPE \
            -u $IOS_UPLOAD_TYPE \
            -w Proj.xcworkspace \
            -c "吧啦吧啦" \
            -b ${updateServerPath}/apkipa/Proj-mobile.${APP_VERSION_CODE}.${APP_VERSION_NAME}-$buildTime.xcarchive \
            -o $ipaPath


#下面是 bugly 上传符号 脚本

#上传符号文件 必须编译完立即上传,每次编译产生的 map 都会变化
            $JAVAHOME1_8/bin/java -jar $ProjRoot/buglyqq-upload-symbol.jar -appid 5fe2f21f91 \
                                    -appkey xxxx \
                                    -bundleid xxxxx \
                                    -version ${APP_VERSION_NAME}.${APP_VERSION_CODE} \
                                    -platform IOS \
                                    -inputSymbol ${updateServerPath}/apkipa/Proj-mobile.${APP_VERSION_CODE}.${APP_VERSION_NAME}-$buildTime.xcarchive/dSYMs/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容