重新上线一个老项目,只做了一些UI修改,其余大部分内容没有变化,但是由于项目的年龄摆在那里,对顺利上线不是特别有信心。
2018.08.31上线,09.02被拒,邮件中提及
"prefs:root=" non-public URL scheme
私有API的使用。其实修改这个错误挺容易的,根据App Store 审核指南中2.5.1 描述:
App 仅可使用公共 API,并且必须在当前发布的 OS 上运行。进一步了解公共 APIs (英文)。及时更新您的 app,在未来的操作系统版本中不再支持的任何过时功能、框架或技术皆应被淘汰。App 使用的 API 和框架应该是为了实现预期用途,并在 app 描述中说明集成详情。例如,HomeKit 框架应提供家居自动化服务,HealthKit 则应该用于保持健康和健身目的,并集成在“健康”app 中。
"prefs:root="一系列跳转设置URL都属于私有API,在苹果机器审核期间,只要代码中存在就会被拒。这句话很重要,我们介绍这些API纯属介绍,不建议使用,当然,如果想使用又想避免被拒,也是有办法,不急,这些在下面有介绍,慢慢看。
1、prefs:root(App-Prefs:root)
在iOS8 ~iOS10之前的版本都是可以使用此API进行跳转(当然,上架的话,审核大概率还是会被拒,在这里仅仅讨论版本使用问题)
以跳转至App相机权限为例:
NSURL *privacyUrl = [NSURL URLWithString:@"prefs:root=Privacy&path=PHOTOS"];
if ([[UIApplication sharedApplication] canOpenURL:privacyUrl]) {
if (@available(iOS 10.0, *)) {
[[UIApplication sharedApplication] openURL:privacyUrl options:@{} completionHandler:nil];
}else{
[[UIApplication sharedApplication] openURL:privacyUrl];
}
}
iOS8
成功跳转(iOS8.1 5s)
进入设置--隐私-- 照片
iOS9~iOS10
需要在Info -> URL Types中新增一个Schemes,URL Schemes中填写 prefs
成功跳转(iOS9.1 5s)
其中iOS10以上应该使用
// Options are specified in the section below for openURL options. An empty options dictionary will result in the same
// behavior as the older openURL call, aside from the fact that this is asynchronous and calls the completion handler rather
// than returning a result.
// The completion handler is called on the main queue.
- (void)openURL:(NSURL*)url options:(NSDictionary<NSString *, id> *)options completionHandler:(void (^ __nullable)(BOOL success))completion NS_AVAILABLE_IOS(10_0) NS_EXTENSION_UNAVAILABLE_IOS("");
跳转的URL的对应的字符串常用的如下:
(两个写法 App-Prefs:root=Xxx&path=XXXX 或者 prefs:root= Xxx&path=XXX)
名称 | 字符串 |
---|---|
通用 | prefs:root=General |
隐私-照相机 | prefs:root=Privacy&path=CAMERA |
隐私-健康 | prefs:root=Privacy&path=HEALTH |
通用-键盘 | prefs:root=General&path=KEYBOARD |
... | .... |
针对通用和隐私(General、Privacy)的话,这个链接的写法很容易,你将设备语言设置为英语,进入Settings,看到页面,一级页面为root(首字母大小),点击进入之后为path(全部大写)
其余的大同小异,只有名称是否大小写的区分,通用与隐私中已经可以包含大部分的功能。
举几个其余的:
(两个写法 App-Prefs:root=&path= 或者 prefs:root=&path=)
名称 | 字符串 |
---|---|
地图 | prefs:root=MAPS |
蓝牙 | prefs:root= Bluetooth |
... | .... |
iOS11中其实也可以使用这种方法进行跳转,但字符串的写法必须只能是App-Prefs:root=
,但是在iOS11对私有API是做了限制,所以之前的写法都只能跳转到Settings首页(如果Settings在后台模式的话,就展示当前所在的页面),无法进入path所指页面
2、UIApplicationOpenSettingsURLString
推荐写法,同时是支持iOS8以上版本
NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
if ([[UIApplication sharedApplication] canOpenURL: url]) {
if (@available(iOS 10.0, *)) {
[[UIApplication sharedApplication] openURL: url options:@{} completionHandler:nil];
}else{
[[UIApplication sharedApplication] openURL: url];
}
}
进入的是App对应的权限界面
其实写了这么多,如果当前需求仅仅是需要相机和相册等权限的开启,直接使用第二种即可,跳转和审核都可以。
(PS:可能存在UIApplicationOpenSettingsURLString跳转到Settings首页的情况,这种是发生在应用没有请求任何权限授予,包括相机、定位等,这样子Settings中不会出现该App的选项。一般不会出现这种情况,写Demo的出现过,这边提及下)
铁头娃 仍使用私有API方法
情况多数出现在使用蓝牙的App设备下
两个方法 :1、跳转的私有API字符串用服务端返回;2、ASCII值进行拼装组合方法
//以蓝牙 App-Prefs:root=Bluetooth 为例
- (NSString *)getBluetoothMethod{
NSData *dataOne = [NSData dataWithBytes:(unsigned char[]){0x41,0x70,0x70,0x2d,0x50,0x72,0x65,0x66,0x73,0x3a,0x72,0x6f,0x6f,0x74,0x3d,0x42,0x6c,0x75,0x65,0x74,0x6f,0x6f,0x74,0x68} length:24];
NSString *method = [[NSString alloc] initWithData:dataOne encoding:NSASCIIStringEncoding];
return method;
}
ASCII值转换可以前往在线编码器
两个方法都是避免代码中出现prefs:root=或者App-Prefs:root,绕过机器审核。
但是,但是,但是,终究是取巧而且iOS11还是不行😢 所以 这块上,在iOS11上,多数App都是提示用户手动去设置打开