AppStore审核、iOS开发证书、iOS开发者帐号、Daily Build

文章出处,原创于 http://HawkingOuYang.com/

我的GitHub


©OYXJ → 以下图片,可能泄漏之前公司的部分商业机密?如果如此,我立即删除;但觉得只是资源的命名规则,应该算不上。

AppStore审核

Distributing iOS Apps With iTunes Connect — 这个很好 !

iOS Provisioning Profile(Certificate)与Code Signing详解

证书申请1
证书申请2

微信分享屏蔽跳转appstore解决方法

Account Management

Delete a device from my developer account to increase the count

How can I Delete an iOS device on my iOS Device list?

Can deleted device be reallocated in the Developer Portal?

What happens to my apps after my developer account membership expires

iOS Developer Enterprise Program membership Renewal Before Expiration

how to remove version of iPhone application from apple app store?

查下项目里哪用到了这个私有api

上架AppStore,资料准备,格式

iOS-AppStore-Review-DevAccount-Certificate_7.jpg

加急审核?

下方图片源自 → appreviewtimes.com
iOS-AppStore-Review-DevAccount-Certificate_AppReview_1.jpg

Apple审核 → Apple

等待审核超过7天写信,我写给Apple的信

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Dear Sir/Ma’am,
According to the regular review period of App Store Review,
which is 7 days (i.e. a workweek) ,
as seen in http://appreviewtimes.com/ And https://developer.apple.com/support/app-review/ ,
but 10 days have been passed, considering that our app submits for review on Nov. 27,
and our app is still in the review status “waiting for review”.
Please kindly make sure that you did not skip our app,
and remember to review our app.
Thank you very much for your effort and time.
iOS Development Team
Dec. 6, 2015. China Time

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Dear Sir/Ma'am,
As the version of 3.0.4, which is already on App Store,
A fatal bug was found in our APP that a ViewController(i.e. “入园离园”)
could not load any data from server,
which caused the relevant module always show blank with only a spinning indicator.
We have so far received tens of thousands of complains from users.
The occurred problem has been solved in version 3.0.5,
and now we need an urgent & fast review of our APP to
ensure the normal operation.
Your nice and timely help will be warmly appreciated.
Thank you very much.
iOS Development Team
Oct. 27, 2015. China Time.

iWoMail 6.3.1 加急审核

情况说明:

解锁了iOS开发者账号,看到沃邮箱6.3.0通过审核了,但是很久还没有上架,顺便把沃邮箱上架了,但是悲剧了。

由于安卓端的问题,把超级登陆的接口给停了,所以沃邮箱iOS6.3.0登录没法用 !

网上搜了一下:能够在App Store上移除最近刚刚发布的软件版本,从而保留上一个版本?结果是:NO!

参考:
how to remove version of iPhone application from apple app store?

我已经看过了。只能是 两种选择:

(1)下架--- 显然不能这么做,因为运营要推广沃邮箱的话,App Store上根本搜索不到沃邮箱。

或者

(2)有一个办法:把 6.2.3的代码 重新打包 成 新版本 6.3.1,然后提交审核,加急审核。

对于(2)的详细说明:
注意1: 从appStore_6.2.3分支, 搞一个 新的分支 appStore_6.3.1分支,Xcode配置,改成 Version 6.3.1 Build 20160125.1 ,这里Version必须大于已经上架的6.3.0 ,
审核被拒绝之后,Version 可以保持不变,只需要递增 build即可,build 按照 日期来填。
注意2: 请测试人员 用6.3.1 覆盖安装 6.3.0,测试一下数据库,会不会奔溃?
注意3: 请服务端人员 把沃邮箱iOS版本6.3.1 的审核状态 改成 审核中。

加急审核的理由如下:

中文:

最近上架的版本(Version 6.3.0 Build 20160108.1)存在一个严重的的bug,服务端的超级登陆接口停用了,导致用户无法登录;但是App Store上无法回滚软件的版本,所以只好拿上一个版本的代码,重新打包 成6.3.1,提交审核,并发起加急审核,希望得到审核人员的帮助,使得新版本6.3.1尽快上架。

英文:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Dear Sir/Ma'am,
As of the LAST binary bundle which we put on App Store ( i.e. Version 6.3.0 Build 20160108.1) ,
we've found a Fatal bug that users can not login by registrating their mobile phones,
which is caused by changing of Server Interface, worse still, Server Interface can not be fixed in a short time,
meanwhile App Store does not support Reverting Version of App,
so we re-make an binary bundle (Version 6.3.1) that is build with exactly the same code with the Version 6.2.3 Build 2015.11.23
(as you can see in App Store review history, this binary bundle was successfully approved),
except one thing ---- Version and Build are different.
So we need an EXPEDITE review to make sure that the fewer users are affected,
the fewer the better, we really appreciate your timely support and your warmly help.
iOS Development Team
Jan. 26, 2016. China Time.

说明:Apple审核的效率越来越高了,以前“两周”,后来“一周”,现在“一两天”,所以一般也不用加急审核,上面这英文是我以前写的,如果现在要加急,用“中文”写也行,因为AppStore审核 三个地点:美国、日本、香港,90%以上的App在美国审核,那边有华裔负责AppStore审核这项工作,有时候还会打电话过来(电话说中文)。

加急审核入口 → Apple

iOS开发证书

iOS开发者帐号

Daily Build

漫谈iOS程序的证书和签名机制

package-ios-ali.py
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
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#!/usr/bin/env python
#coding:utf-8
import os,sys,time
import subprocess
def copyconfig(projectaddr,resourceaddr,version,versionstring):
filename='%s/anbang_ios/anbang_ios-Info.plist' %(projectaddr)
try:
pcommand='cp -rf %s/ALY/AppIcon.appiconset %s/anbang_ios/Images.xcassets/AppIcon.appiconset' %(resourceaddr,projectaddr)
print 'excecute command:[%s]' %pcommand
print os.system(pcommand)
pcommand='cp -rf %s/ALY/AddressDefine.h %s/anbang_ios/Define' %(resourceaddr,projectaddr)
print 'excecute command:[%s]' %pcommand
print os.system(pcommand)
pcommand='cp -rf %s/ALY/anbang_ios-Info.plist %s/anbang_ios/' %(resourceaddr,projectaddr)
print 'excecute command:[%s]' %pcommand
print os.system(pcommand)
pcommand='rm -rf %s/ABOrganization/*' %(projectaddr)
print 'excecute command:[%s]' %pcommand
print os.system(pcommand)
pcommand='cp -rf %s/ALY/1435646730000.db %s/anbang_ios/ABOrganization/' %(resourceaddr,projectaddr)
print 'excecute command:[%s]' %pcommand
print os.system(pcommand)
pcommand="sed -i.bak '/<key>CFBundleShortVersionString<\/key>/,/<string>.*<\/string>/ s@<string>.*</string>@<string>%s</string>@' %s" %(versionstring,filename)
print 'excecute command:[%s]' %pcommand
print os.system(pcommand)
pcommand="sed -i.bak '/<key>CFBundleVersion<\/key>/,/<string>.*<\/string>/ s@<string>.*</string>@<string>%s</string>@' %s" %(version,filename)
print 'excecute command:[%s]' %pcommand
print os.system(pcommand)
except Exception,e:
print e
print 'Now will exit building'
sys.exit(1)
def build_ios(projectaddr,resourceaddr,destaddr,path,version):
file='%s/ALY/bbchat.mobileprovision' %(resourceaddr)
file2='%s/anbang_ios' %(projectaddr)
name='bbchat.ipa'
try:
os.chdir(projectaddr)
pcommand='security unlock-keychain -p "asiainfo" ~/Library/Keychains/login.keychain'
print 'excecute command:[%s]' %pcommand
print 'command result=[%s]' %(os.system(pcommand))
pcommand='xcodebuild -configuration "Release" -target "anbang_ios" -sdk iphoneos clean build'
print 'excecute command:[%s]' %pcommand
print 'command result=[%s]' %(os.system(pcommand))
#pcommand='xcrun -sdk iphoneos PackageApplication -v /Users/apple/.jenkins/jobs/ios-ali/workspace/build/Release-iphoneos/anbang_ios.app -o /opt/bbchat.ipa --sign "iPhone Distribution: ANBANG INSURANCE LTD." --embed %s' %(file)
pcommand='xcrun -sdk iphoneos PackageApplication -v %s/build/Release-iphoneos/anbang_ios.app -o /opt/packagesource/ios/bbchat.ipa --sign "iPhone Distribution: ANBANG INSURANCE LTD." --embed %s' %(projectaddr,file)
print 'excecute command:[%s]' %pcommand
print 'command result=[%s]' %(os.system(pcommand))
#ssh(destaddr,name,path,version)
os.system('/opt/iosupload.sh' + ' ' + destaddr +'/'+ name)
os.chdir(destaddr)
pcommand='rm -rf *'
print 'excecute command:[%s]' %pcommand
print os.system(pcommand)
except Exception,e:
print e
print 'Now will exit building'
sys.exit(1)
if __name__ == '__main__':
projectaddr='/Users/apple/.jenkins/jobs/ios-ali/workspace'
resourceaddr='/opt/resource/ios/reset'
destaddr='/opt/packagesource/ios'
version=sys.argv[1]
versionstring=sys.argv[2]
path='ALIYUN'
copyconfig(projectaddr,resourceaddr,version,versionstring)
time.sleep(2)
build_ios(projectaddr,resourceaddr,destaddr,version)
打包命名(待改进)

iOS-AppStore-Review-DevAccount-Certificate_1.jpg

iOS_AppStore
iOS_AdHoc
iOS_Enterprise
iOS_Dev
调整顺序:
bundleIDversion显示版本号build内部构建版本号iOSAppStore打包日期 .ipa
bundleID
version显示版本号build内部构建版本号iOSEnterprise打包日期 .ipa
bundleIDversion显示版本号build内部构建版本号iOSAdHoc打包日期 .ipa
bundleID
version显示版本号build内部构建版本号iOSDev打包日期 .ipa

把ipa的名字,写详细了。
cn.wo.3ikids.parents互动宝宝家长端3.1.0AppStore151113 请更改为更详细的命名
cn.wo.3ikids.parents互动宝宝家长端_version3.1.0_build20151116_AppStore151116
其中:version3.1.0 ----这里 3.1.0 为显示版本号(在AppStore中显示的版本号)
build20151116 ---这里 20151116 为构建版本号(这个开发人员内部使用)
AppStore151116 --这里151116 为2015年11月16号,打包ipa,用于上传AppStore。
对应Xcode中
iOS-AppStore-Review-DevAccount-Certificate_2.jpg

配置文件命名(待改进)

iOS-AppStore-Review-DevAccount-Certificate_3.jpg

iOS-AppStore-Review-DevAccount-Certificate_4.jpg

配置文件:
bundleIDiOS_AppStore配置文件制作日期 .mobileprofile
bundleIDiOS_InHouse配置文件制作日期 .mobileprofile
bundleIDiOS_AdHoc配置文件制作日期 .mobileprofile
bundleIDiOS_Dev配置文件制作日期 .mobileprofile

证书命名(待改进)

iOS-AppStore-Review-DevAccount-Certificate_5.jpg

总体命名(待改进)

iOS-AppStore-Review-DevAccount-Certificate_6.jpg

打包之后,保留的文件(待改进)

iOS-AppStore-Review-DevAccount-Certificate_8.jpg

版本命名规则

版本号 命名错误: 只能是3位整数,用英文句号 . 隔开。
以前可以4位整数的,苹果更严格了。貌似现在 又可以 4位整数了 ?

CFBundleVersion in the Info.plist Upload Error (这个好,权威)

CFBundleVersion must be a period separated list of at most three non negative integers

Efficient way to compare version strings in Java

1
2
3
4
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
NSString *appDisplayVersion = [infoDictionary objectForKey:@"CFBundleShortVersionString"];//当前App显示版本号
NSString *appBuildVersion = [infoDictionary objectForKey:@"CFBundleVersion"];//当前App构建版本号
BOOL isNewVersion = [version compare:appDisplayVersion options:NSNumericSearch] == NSOrderedDescending;//比较 `数字`,降序。

这里,iOS版本比较逻辑 与 下面Java逻辑 一致。

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
26
27
28
29
30
31
/**
* Compares two version strings.
*
* Use this instead of String.compareTo() for a non-lexicographical
* comparison that works for version strings. e.g. "1.10".compareTo("1.6").
*
* @note It does not work if "1.10" is supposed to be equal to "1.10.0".
*
* @param str1 a string of ordinal numbers separated by decimal points.
* @param str2 a string of ordinal numbers separated by decimal points.
* @return The result is a negative integer if str1 is _numerically_ less than str2.
* The result is a positive integer if str1 is _numerically_ greater than str2.
* The result is zero if the strings are _numerically_ equal.
*/
public static int versionCompare(String str1, String str2) {
String[] vals1 = str1.split("\\.");
String[] vals2 = str2.split("\\.");
int i = 0;
// set index to first non-equal ordinal or length of shortest version string
while (i < vals1.length && i < vals2.length && vals1[i].equals(vals2[i])) {
i++;
}
// compare first non-equal ordinal number
if (i < vals1.length && i < vals2.length) {
int diff = Integer.valueOf(vals1[i]).compareTo(Integer.valueOf(vals2[i]));
return Integer.signum(diff);
}
// the strings are equal or one string is a substring of the other
// e.g. "1.2.3" = "1.2.3" or "1.2.3" < "1.2.3.4"
return Integer.signum(vals1.length - vals2.length);
}

版本号 递增命名,比如:

version 2.0 (用户看到的)

build 2.0.2016090901 (开发者 看到的)

说明:2.0.2016090901 含义是 目标版本2.0,在2016年09月09日这天,第01次 提交给AppStore审核。

当时有一个问题:

安卓的标准 versionCode是数字

服务端,比较版本(依赖于Android),使用 整型。

iOS端,比较版本,使用 字符。

所以,服务端要求: iOS端 按照Android 的逻辑走。

但是,iOS端 version build 命名是这样的:

1、第一版 version1.0 build1.0.14
2、第二版 version1.1 build1.1.2
3、第三版 version1.1.1 build1.1.1.0

iOS端 应该 要求 服务端走这种逻辑,如下:(但是 现在 服务端 走Android的“整型 比较版本”的逻辑)

所以:iOS端 的 version 和 build 命名,要按照 Android走,同时 iOS写代码,把 “字符 版本” 变成 “整型 版本” (不得不说,这样真不靠谱)。

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
26
27
28
29
/**
* 输入版本号 例如1.1.1 返回 10101 五位数的版本号
* @note (逻辑跟随Andriod,不得不说,这样真不靠谱)
*
* @param version 本地的版本号
*
* @return 5位数的版本号
*/
+ ( NSUInteger)intergerVersionWithVersionString:(NSString *)version
{
NSArray * versionArray = [version componentsSeparatedByString:@"."];
if (versionArray.count<3) {
return 0; /* 避免 崩溃 */
}
NSString *localFirst = versionArray[0];
NSString *localSecond = versionArray[1];
NSString *localThird = versionArray[2];
NSUInteger localFirstInteger = [localFirst integerValue];
NSUInteger localSecondInteger = [localSecond integerValue];
NSUInteger localThirdInteger = [localThird integerValue];
NSUInteger localVersionInteger = localFirstInteger *10000 +
localSecondInteger *100 +
localThirdInteger;
return localVersionInteger;
}