# iOS 常见问题
# 1. 集成时常见问题
# 1.1 集成SDK的最低配置是什么?
答:FinClip小程序SDK支持iOS 9 以及 iOS 9以上,低于iOS 9的系统版本不支持。
# 1.2 是否支持bitcode?
答:2.34.5之前的版本不支持,2.34.5之后(含2.34.5)支持。2.36.13开始去除bitcode支持。
# 1.3 工程报错,找不到某个类别方法,怎么办?
答:这是因为没有配置-ObjC
,SDK中有创建Catogery,需要在Build Setting
中的 Other Linker Flags
中添加-ObjC
。
# 1.4 初始化SDK的时候,有哪些参数是必须配置的?
答:SDK版本低于2.34.1时,sdkSecret
、sdkKey
、apiServer
、apiPrefix
都是必须配置的;SDK版本高于2.34.1(含2.34.1)时,我们做了一些优化,去掉了apiPrefix,所以sdkSecret
、sdkKey
、apiServer
是必须配置的。
FATStoreConfig *storeConfig = [[FATStoreConfig alloc] init]; storeConfig.sdkKey = @"这里填上的SDK Key"; storeConfig.sdkSecret = @"这里填上SDK secret"; storeConfig.apiServer = @"这里填上你们的服务器地址"; // 例如:https://api.finclip.com; storeConfig.apiPrefix = @"/api/v1/mop"; // 2.34.1以上可不配置apiPrefix FATConfig *config = [FATConfig configWithStoreConfigs:@[storeConfig]]; [[FATClient sharedClient] initWithConfig:config error:nil];
已复制代码
另外,如果配置了currentUserId
,则数据会缓存到该目录下,便于多账号切换时,加载不同账户下的数据。
# 1.5 为什么注册的自定义小程序API不起作用?
答:在注册自定义API时,会判断当前的小程序SDK是否初始化成功了。如果没有初始化成功,那么注册自定义Api就不会成功。
所以,注册自定义API前,一定要保证小程序已经初始化成功了。
# 1.6 小程序是否支持横竖屏切换或强制横屏?
答:支持。
如果想要小程序支持横竖屏切换,首先需要在iOS 工程的【General】 -> 【Deployment Info】 -> Device Orientation】中勾选Portrait、Landscape Left、Landscape Right 三个选项。
然后,在小程序的app.json的window 中配置[pageOrientation],其值可选:auto / portrait / landscape。
或者,也可以单独在页面对应的json 配置中设置[pageOrientation]。
如果是iPad,想要允许设备支持横竖屏切换,需要设置 app.json的resizable。其值为boolean类型。
# 1.7 如何配置SDK批量更新的小程序个数?
答:在 FATConfig 中有一个属性appletIntervalUpdateLimit,该值默认为3。也就是后台自动检车版本时,只会检测最近使用的三个小程序。在初始化SDK的时候,可以修改appletIntervalUpdateLimit,取值范围0~50。
# 1.8 如何试用major版本的SDK?
答:有一些功能怕影响已有的模块,所以我们将其放置在major版本的SDK中。 如果有这部分功能有需要的用户,可以提前集成majorSDK来试用或提前开发自己的小程序。
major版本的SDK 里面可能会包含一些还未充分测试,稳定性不太好的功能。体验major版本SDK也有两种方式:手动集成和pod集成。
手动集成的话,跟正式版版本的手动集成流程一样,也是下载SDK,放进工程,修改工程配置等,这里就不再赘述了。
pod集成这里重点讲一下! 由于major版本不太稳定,所以不能上传至cocoapods源,所以我们将major版sdk 上传至凡泰自己的仓库源里。集成步骤如下:
1.添加凡泰仓库源
source 'https://git.finogeeks.com/cocoapods/FinPods'
已复制代码
注意,如果之前的podfile中没有添加cocoapods的源,需要添加上。
# 这俩根据自己的实际情况选一个添加即可 source 'https://github.com/CocoaPods/Specs.git' source 'https://cdn.cocoapods.org/'
已复制代码
2.podfile中指定SDK的版本
pod 'FinApplet', '2.37.0-alpha20220416v03' pod 'FinAppletExt', '2.37.0-alpha20220416v03'
已复制代码
3.pod install
安装依赖,或者pod update
更新依赖即可。
# 2. 使用时常见问题
# 2.1 如何启动小程序?
答:调用如下API即可:
[[FATClient sharedClient] startRemoteApplet:appId startParams:startParams InParentViewController:viewController completion:^(BOOL result, NSError *error) { NSLog(@"result:%d---error:%@", result, error); }];
已复制代码
# 2.2 是否有小程序打开时常见的错误码与排查方式?
答:常见的打开小程序失败的提示有如下 8 种:
- appId or appTitle is nil。 这是因为启动小程序时,没有配置appId;或者后台编辑小程序基本信息时,没有配置小程序名称。
- copyResources failed 这是因为将 下载的
小程序包
或者基础库包
移动到运行目录失败,这种情况大多是因为编译出来的小程序zip
包或者基础库zip
包有问题导致的。 - service.html not found! 这是因为编译出来的
小程序zip
包中 缺失service.html
,这种情况可能是因为编译出来的小程序zip
有问题导致的。 - copy app file failed! 这是因为将下载的
小程序zip
移动到缓存目录失败,极少会出现这种问题。 - 服务异常,获取小程序详情失败 这种情况一般是调用获取小程序详情的接口失败,一般是后台服务有问题,或者是小程序配置有问题。 记得,检查
apiPrefix
是否 正确配置为api/v1/mop
。 - 合作已终止。 这种情况,一般是因为管理后台终止了与该应用(该对应bundleId)的合作。具体请咨询开放平台,或者后台管理员。
- 服务不可用。 这种情况,一般是小程序还未关联应用,或者是后台有问题。
- 服务异常,返回小程序详情数据异常。 这种情况,一般是因为后台服务出错,导致返回的数据格式不合法。
# 2.3 如何为小程序增加微信分享功能?
答:这里主要有如下 3 种方式:
- 将转发功能修改成微信分享;
- 自定义微信分享接口,然后小程序中调用自定义的微信分享接口。
- 直接引用分享SDK,可参考我们的集成SDK的说明
# 2.3.1 将转发功能修改为微信分享
FinClip小程序SDK会将转发事件通过代理传递出来,所以只需要为[FATClient sharedClient].buttonOpenTypeDelegate
设置一个实现的对象。
然后,就可以在如下代理方法中,获取到转发时的信息:
/** 转发事件 当你点击小程序右上角更多里的转发菜单时,会触发小程序里shareAppMessage方法,然后回调到原生该方法 @param contentInfo 小程序相关信息,里面包含小程序id、小程序名称、小程序图标、小程序截图(5:4)等。 { appAvatar = "小程序图标地址"; appDescription = "小程序的描述信息"; appId = "小程序id"; appInfo = {}; // 客户可在appInfo中自定义字段,appInfo内容会透传 appStartParams = { path = "点击转发时的小程序页面路径"; }; appThumbnail = "小程序封面图的路径,可能是网络路径或者本地路径,宽高比是5:4"; appTitle = "小程序名称"; userId = "小程序开发者id"; } @param completion 执行完后的回调,如果你转发操作执行完后,希望告知小程序端转发结果,就需要调用该block。 */ - (BOOL)forwardAppletWithInfo:(NSDictionary *)contentInfo completion:(void (^)(FATExtensionCode code, NSDictionary *result))completion;
已复制代码
其中appInfo
是小程序在onShareAppMessage
新增的属性,内容可以定义各种键值对。
最后,调用微信分享SDK的分享小程序接口即可。
# 2.3.2 自定义微信分享接口,然后小程序中调用自定义的微信分享接口。
因为FinClip小程序SDK,支持自定义小程序API,所以我们可以先自定义一个分享API。在小程序SDK初始化之后,可以像如下这样注册一个小程序API:
[[FATClient sharedClient] registerExtensionApi:@"shareToWechat" handle:^(id param, FATExtensionApiCallback callback) { // 这里可以获取到param,也就是小程序内传过去来的对象。 // 然后调用微信分享接口,分享即可。 callback(FATExtensionCodeSuccess, nil); }];
已复制代码
同时,在小程序根目录创建 FinClipConf.js
文件,配置示例如下:
module.exports = { extApi:[ { //普通交互API name: 'shareToWechat', //扩展api名 该api必须Native方实现了 params: { //扩展api 的参数格式,可以只列必须的属性 path: '', title: '', description: '' } } ] }
已复制代码
最后,在小程序里调用自定义的微信分享接口即可:
ft.shareToWechat
已复制代码
# 2.4 为何无法调用request、uploadFile、downloadFile接口?抓包也没看到接口调用过程。
答:如果上述三个接口无法调用,一般会看到如下的错误信息:url not in domain list
。
这是因为没有在后台给小程序配置域名,配置域名的方式与微信的域名配置类似,都是要单独配置request/uploadFile/downloadFile 的域名。
# 2.5 为何在小程序的 webView 组件中无法加载网络链接?
答:如果你在使用webView打开链接时,提示 不支持打开非业务域名xxxxxxxx,请重新配置
。那是因为没有在管理平台配置业务域名,这个业务域名是webView加载链接的域。
# 2.6 如何设置启动小程序时的转场动画方式?
答:现在启动小程序有如下 2 种动画方式:
- present的方式;
- 类似push的动画方式。
在调用如下启动函数时,设置transitionStyle
即可,这个枚举值有:FATTranstionStyleUp、FATTranstionStylePush。
[[FATClient sharedClient] startRemoteApplet:appId startParams:appStartParams InParentViewController:self transitionStyle:FATTranstionStyleUp completion:^(BOOL result, NSError *error) { NSLog(@"result:%d---error:%@", result, error); }];
已复制代码
# 2.7 如何注册自定义小程序API?
答:请参考iOS 注册自定义的小程序API进行对应操作
# 2.8 如何获取小程序当前页面截图?
答:调用如下函数即可获取小程序当前页面的截图(截图是5:4)。
UIImage *coverImage = [[FATClient sharedClient] getCurrentAppletImage];
已复制代码
# 2.9 小程序右上角的更多按钮里的菜单支持自定义吗?如果支持,要怎么实现?
答:支持。
需要实现两个代理方法。首先,自定义一个FATClientHelper
类,实现FATAppletMoreMenuDelegate
协议。
#import <Foundation/Foundation.h> #import <FinApplet/FinApplet.h> @interface FATClientHelper : NSObject<FATAppletMoreMenuDelegate> + (instancetype)shareInstance; @end
已复制代码
然后,在SDK初始化成功后后,设置SDK的代理为 FATClientHelper
对象。
示例代码:
[[FATClient sharedClient] initWithConfig:config error:nil]; [FATClient sharedClient].moreMenuDelegate = [FATClientHelper shareInstance];
已复制代码
最后,在FATClientHelper
中实现,如下协议方法:
// 返回要注入的菜单对象,菜单对象是要实现 FATAppletMenuProtocol 协议的 // 菜单对象分为两种类型(默认为Common类型): // 1.OnMiniProgram类型:需要后台配置+小程序配置,取相同menuId的集合显示 // 2.Common类型:配置则显示 // PS: 这里兼容旧版本,若后台未升级版本,或后台升级版本后未配置,则仅需要适配菜单对象的menuId为NSString类型 - (NSArray<id<FATAppletMenuProtocol>> *)customMenusInApplet:(FATAppletInfo *)appletInfo atPath:(NSString *)path { FATCustomMenuModel *favModel1 = [[FATCustomMenuModel alloc] init]; favModel1.menuId = @"WXShareAPPFriends"; favModel1.menuTitle = @"微信好友"; favModel1.menuIconImage = [UIImage imageNamed:@"minipro_list_wx_chat"]; favModel1.menuType = FATAppletMenuStyleOnMiniProgram; FATCustomMenuModel *favModel2 = [[FATCustomMenuModel alloc] init]; favModel2.menuId = @"WXShareAPPMoments"; favModel2.menuTitle = @"微信朋友圈"; favModel2.menuIconImage = [UIImage imageNamed:@"minipro_list_wx_monents"]; favModel2.menuType = FATAppletMenuStyleOnMiniProgram; FATCustomMenuModel *favModel3 = [[FATCustomMenuModel alloc] init]; favModel3.menuId = @"Restart"; favModel3.menuTitle = @"重启"; favModel3.menuIconImage = [UIImage imageNamed:@"minipro_list_restart"]; favModel3.menuType = FATAppletMenuStyleCommon; return @[favModel1, favModel2, favModel3]; } // 点击自定义菜单时的事件(旧版,后台未升级或升级后未配置菜单时使用) - (void)customMenu:(id<FATAppletMenuProtocol>)customMenu inApplet:(FATAppletInfo *)appletInfo didClickAtPath:(NSString *)path { NSLog(@"点击了%@",customMenu.menuTitle); NSLog(@"path = %@",path); } // 点击自定义菜单时的事件(新版,后台与小程序配置时使用) - (void)clickCustomItemMenuWithInfo:(NSDictionary *)contentInfo completion:(void (^)(FATExtensionCode, NSDictionary *))completion { /** contentInfo 中包含 { @"title": @"标题", @"description": @"描述", @"imageUrl": @"图片路径", @"path": @"点击时的小程序页面路径"", @"menuId": @"点击的菜单按钮标识", @"params": self.params // 原始参数数据,由小程序提供 } */ // 小程序回调调用,通知小程序点击事件处理情况 completion(FATExtensionCodeSuccess, contentInfo); }
已复制代码
# 2.10 是否支持小程序某页面完全隐藏导航栏?如果支持,该如何实现?
答:支持。
像微信、支付宝、百度等小程序的navigationStyle
有 default/custom
两个值,而FinClip小程序SDK在此基础上,新增了一个hide
,即有default/custom/hide
三个值。
所以在需要隐藏导航栏的页面,设置navigationStyle
为 hide
即可。
# 2.11 如何设置灰度发布自定义规则?
答:小程序SDK的FATAppletConfigurationDelegate
中一个协议方法:
- (NSDictionary *)grayExtensionWithAppletId:(NSString *)appletId
已复制代码
实现这个协议方法即可。
示例代码如下:
/// 小程序灰度扩展参数 /// @param appletId 小程序id - (NSDictionary *)grayExtensionWithAppletId:(NSString *)appletId { NSDictionary *grayExtension = @{@"key1":@"value1"}; // if ([appletId isEqualToString:@"5e017a61c21ecf0001343e31"]) { // grayExtension = @{@"fckey1":@"fcvalue1"}; // } return grayExtension; }
已复制代码
然后,小程序SDK在加载小程序时,会调用该协议方法获取小程序的灰度扩展参数,透传给后台服务匹配相关规则。
注意
由于 FinClip 小程序未提供用户体系,当您创建灰度发布,选择「指定用户发布」时,需要通过小程序自定义 API 的形式,将 App 中的用户信息传入小程序,小程序仅在此时才可以按照指定用户发布(使用自定义 API 传入用户 ID 时,默认的规则 ID 为 xUserId
)。
# 2.12 小程序中加载网页失败怎么办?
答:小程序加载网页失败时,可以打开SDK的Log日志开关。当然,错误信息也会在 webView的binderror
回调中返回。
例如,如果看到如下这样的错误信息:
Code=-1022 "The resource could not be loaded because the App Transport Security policy requires the use of a secure connection."
已复制代码
分析得知是因为网络地址是http协议的,需要在app工程的info.plist中配置App Transport Security Settings -> Allow Arbitrary Loads为YES。
# 2.13 小程序SDK是否支持暗黑模式的适配?
答:支持。
小程序SDK初始化时,FATUIConfig类中有一个属性,只需要设置一下即可uiconfig.autoAdaptDarkMode = YES;
。 小程序SDK中的暗黑模式适配,包括 更多 菜单页、关于页面、投诉与反馈页面。小程序的导航栏颜色不受暗黑模式影响。
# 2.14 小程序SDK支持禁用权限申请吗?
我们的APP是金融类型的app,对于权限,尤其是敏感权限(比如定位)等的控制非常重要,我们希望SDK不会主动申请权限,而是由APP在合适的时机申请权限,这样可以吗?
答:支持。
小程序SDK的config类中有一个属性disableAuthorize,可以控制权限的申请。
如果该属性不配置,或者配置为NO,那么小程序SDK中使用到还未用户授权的权限时,会向用户申请; 如果该属性设置为YES(config.disableAuthorize = YES;
),那么当小程序SDK使用到还未用户授权的api时,会在api的失败回调中返回失败,errMsg中包含失败的原因(比如chooseImage:fail 无相册访问权限)。
另外小程序SDK的config类中有一个属性appletAutoAuthorize,可以控制小程序向SDK申请权限。 如果该属性不配置,或者配置为NO,那么用户在使用小程序需要使用某项权限时,会弹出提示框询问用户授权是否同意申请权限,用户同意后,小程序向SDK申请权限,如用户拒绝,则不会向SDK申请权限并返回失败,errMsg中包含失败的原因(比如chooseImage:fail 无相册访问权限);如果该属性设置为YES,则表示自动向SDK申请权限,不会弹出授权提示。
# 2.15 支持替换返回按钮icon吗?要如何替换?
答:支持。
只需要在工程里放一个png图片,然后命名为fin_btn_navi_back即可,需要通过mainBundle 能访问到哦。
# 2.16 是否支持小程序中打开safari?
答:支持。
虽然,我们SDK中没有使小程序打开手机safari,并且加载指定url的api。但是我们SDK 支持注册自定义api,所以通过注入自定义H5 api,可以实现该功能。 因为注入自定义api分两个场景:注册小程序使用的api 和 注册小程序中的H5使用的api。 SDK 为这两种场景分别提供了函数,并且他们的处理流程也不同,所以要分开讲。
小程序中的H5里打开safari 首先,初始化SDK之后,注册一个自定义api,代码片段示例如下:
[[FATClient sharedClient] fat_registerWebApi:@"openInSafari" handler:^(FATAppletInfo *appletInfo, id param, FATExtensionApiCallback callback) { NSString *url = param[@"url"]; [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]]; callback(FATExtensionCodeSuccess, nil); }];
已复制代码
然后,加载H5的页面中引入 FinClip 小程序jssdk。
最后,在H5中的逻辑中,调用注册的自定义api:
window.FinChatJSBridge.invoke('openInSafari', {url:'https://www.finclip.com'}, (result) => { console.log(result) });
已复制代码
小程序中打开safari
首先,注册小程序用的自定义api,片段示例:
[[FATClient sharedClient] registerExtensionApi:@"openInSafari" handle:^(id param, FATExtensionApiCallback callback) { NSString *url = param[@"url"]; [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@""]]; callback(FATExtensionCodeSuccess, nil); }];
已复制代码
然后,小程序的根目录FinClipConf.js
中,配置自定义的api。
module.exports = { extApi:[ { name: 'openInSafari', params: { url: '' } } ] }
已复制代码
最后,小程序中调用该自定义即可:
ft.openInSafari({ url:'https://www.baidu.com', success: function (res) { console.log("startRecord success"); console.log(res); }, fail: function (res) { console.log("startRecord fail"); console.log(res); } });
已复制代码
# 2.17 小程序中支持获取到启动小程序的参数?如何获取?
答:支持。 但小程序中只能获取到启动参数里的query参数。
query里参数会被转成json,小程序可以在生命周期事件onLaunch(options)、onShow(options) 的options中获取。
比如,以如下参数启动小程序:
NSDictionary *startParam = @{ @"query":@"key1=value1&key2=value2", @"path":@"pages/showToast/showToast" }; [[FATClient sharedClient] startRemoteApplet:@"afdfddfdfdf" startParams:startParam InParentViewController:self completion:nil];
已复制代码
那么,在小程序的生命周期事件中获取启动参数:
onLaunch(options) { console.log("App onLaunch =====>" + JSON.stringify(options)) //options.query.key1 //options.path }, onShow(options) { // Do something when show. console.log("App onShow =====>" + JSON.stringify(options)) //options.query.key1 //options.path },
已复制代码
# 2.18 SDK 能设置UserAgent吗?如何设置?
答:支持。
FATUIConfig中有个appendingCustomUserAgent的配置项,你设置的内容会添加到小程序页面对应的webView的userAgent中。
示例:
FATUIConfig *uiConfig = [[FATUIConfig alloc] init];//[FATClientHelper uiConfig]; uiConfig.progressBarColor = [UIColor redColor]; // 添加userAgent内容 uiConfig.appendingCustomUserAgent = @"custom agent"; [[FATClient sharedClient] initWithConfig:config uiConfig:uiConfig error:nil];
已复制代码
# 2.19 怎么在小程序中实现第三方登录?
# 1.集成 FinClip 小程序 SDK( FinClip 小程序 SDK)
开发者首先需要集成 FinClip 小程序 SDK,集成指南请参照 FinClip 小程序开放平台 iOS 集成文档,开放平台已有详尽的 iOS 集成文档,此处不再赘述。
# 2.自定义小程序接口以实现授权登录,获取用户信息,获取登录状态等功能
为了让小程序能过获取到小程序以外的 APP 数据,需要注册小程序自定义接口,自定义接口具体说明请参照 FinClip 小程序开放平台-自定义小程序接口。下面示例中的参数,均由开发者自行决定,本文仅为示范。
- 自定义授权登录 login 接口
@property (nonatomic,strong) FATExtensionApiCallback callBack; [[FATClient sharedClient] registerExtensionApi:@"login" handle:^(id param, FATExtensionApiCallback callback) { self.callBack = callback; // 进行三方登录。 [self thirdLogin]; }]; - (void)thirdLogin { // ToDo 处理三方登录的逻辑 拿到结果后,将想要发送给小程序的信息进行回调。由开发者自行决定发生什么信息, FinClip 只做传递,不会进行保存 // For example 微信三方登录的文档 https://developers.weixin.qq.com/doc/oplatform/Mobile_App/WeChat_Login/Development_Guide.html self.callBack(FATExtensionCodeSuccess, @{@"code": @"success", @"openid": @"XXXXXXXXXXXXXXXXX"}); }
已复制代码
- 自定义获取用户信息 getUserProfile 接口
[[FATClient sharedClient]registerExtensionApi:@"getUserProfile" handle:^(id param, FATExtensionApiCallback callback) { NSDictionary *userInfo = @{@"nickName": @"张三", @"avatarUrl": @"", @"gender": @1, @"country": @"中国", @"province": @"广东省", @"city": @"深圳",@"language": @"zh_CN"}; NSDictionary *resDic = @{@"userInfo": userInfo}; callback(FATExtensionCodeSuccess, resDic); }];
已复制代码
- 自定义检查用户token的checkSession 接口
[[FATClient sharedClient] registerExtensionApi:@"checkSession" handle:^(id param, FATExtensionApiCallback callback) { // For example if ([param[@"code"] intValue] == 1) { // ToDo something } }];
已复制代码
# 2.20 是否支持把SDK中“小程序”文案替换为其它名称?
答:支持。
FATUIConfig中有个appletText的配置项,你设置的内容会替换显示原来的“小程序”文案。
示例:
FATUIConfig *uiConfig = [[FATUIConfig alloc] init];//[FATClientHelper uiConfig]; // 把“小程序”替换为“x应用” uiConfig.appletText = @"x应用"; [[FATClient sharedClient] initWithConfig:config uiConfig:uiConfig error:nil];
已复制代码
# 2.21 数据上报时,是否会对上报的数据进行压缩?
答:数据上报时,SDK默认不对上报的数据进行压缩,如果要开启压缩,可以通过SDK初始化配置enableApmDataCompression参数为YES来实现。
示例:
FATStoreConfig *storeConfig = [[FATStoreConfig alloc] init]; storeConfig.sdkKey = @"这里填上的SDK Key"; storeConfig.sdkSecret = @"这里填上SDK secret"; storeConfig.apiServer = @"这里填上你们的服务器地址"; // 例如:https://api.finclip.com; FATConfig *config = [FATConfig configWithStoreConfigs:@[storeConfig]]; config.enableApmDataCompression = YES;
已复制代码
# 2.22 是否支持禁用获取监管信息的小程序API?
答:支持。
SDK默认允许小程序调用获取监管信息的小程序API(getSuperviseInfo),如果要禁用,则可以通过SDK初始化配置disableGetSuperviseInfo参数为YES来实现。
示例:
FATStoreConfig *storeConfig = [[FATStoreConfig alloc] init]; storeConfig.sdkKey = @"这里填上的SDK Key"; storeConfig.sdkSecret = @"这里填上SDK secret"; storeConfig.apiServer = @"这里填上你们的服务器地址"; // 例如:https://api.finclip.com; FATConfig *config = [FATConfig configWithStoreConfigs:@[storeConfig]]; config.disableGetSuperviseInfo = YES;
已复制代码
禁止后,小程序调用getSuperviseInfo
时将会收到getSuperviseInfo:fail disabled
回调
# 2.23 是否支持打开体验版小程序?
答:支持。
平台支持为小程序配置体验版本和体验成员,拥有体验权限的成员能够打开体验版小程序。
使用体验版小程序的步骤:
在平台中上传小程序,并为小程序配置体验版,配置方式请参考小程序开发-调试
在初始化SDK的时候传入用户ID:
FATStoreConfig *storeConfig = [[FATStoreConfig alloc] init]; storeConfig.sdkKey = @"这里填上的SDK Key"; storeConfig.sdkSecret = @"这里填上SDK secret"; storeConfig.apiServer = @"这里填上你们的服务器地址"; // 例如:https://api.finclip.com; FATConfig *config = [FATConfig configWithStoreConfigs:@[storeConfig]]; config.currentUserId = @"userId";
已复制代码
只有当传入的用户ID在小程序配置的成员列表中时,才能打开体验版小程序,否则在打开小程序的时候,会提示“无体验权限”。
- 通过调用SDK提供的接口打开小程序,接口请参考二维码打开小程序
# 2.24 能否支持离线小程序,提高首次启动速度?
答:自2.35.1版本开始,可配置离线小程序包和离线基础库包的路径。在首次启动时,打开本地的离线小程序。同时检查更新,拉取最新版本小程序,以备下次打开小程序时使用。
获取离线小程序包和离线基础库包的方式,见下图:
示例代码如下:
FATAppletRequest *request = [[FATAppletRequest alloc] init]; //appletId可以从https://www.finclip.com/mop/mechanism/#/Applet/my 页面中小程序列表获取 request.appletId = @"61ee725a8bc99400018e1f7c"; request.apiServer = @"https://api.finclip.com"; //离线小程序压缩包可以从我的小程序->小程序列表->详情->导出离线包->小程序 下载 request.offlineMiniprogramZipPath = [[NSBundle mainBundle] pathForResource:@"hahahhah" ofType:@"zip"]; //离线基础库可以从我的小程序->小程序列表->详情->导出离线包->小程序基础库 下载 request.offlineFrameworkZipPath = [[NSBundle mainBundle] pathForResource:@"framework-2.12.3" ofType:@"zip"]; [[FATClient sharedClient] startAppletWithRequest:request InParentViewController:self.window.rootViewController completion:^(BOOL result, FATError *error) { NSLog(@"打开小程序11:%@", error); } closeCompletion:^{ NSLog(@"关闭小程序11"); }];
已复制代码
# 2.25 是否支持iOS14.3以下系统使用WebRTC功能?
答:支持。平台通过二次封装GoogleWebRTC库实现在iOS9以上系统实现WebRTC的相关功能。
使用步骤如下:
- 在 Xcode 项目的Podfile文件中添加对WebRTC-SDK的依赖:
pod 'FinAppletWebRTC'
已复制代码
- 引入WebRTC-SDK的头文件:
#import <FinAppletWebRTC/FinAppletWebRTC.h>
已复制代码
- 注册WebRTC组件:
// WebRTC初始化 [FATWebRTCComponent registerComponent]
已复制代码
完成以上步骤后就可以在小程序中调用我们提供的WebRTC的Api实现相关功能。
# 2.26 MapSDK的作用和如何使用
答:MapSDK支持Map组件及位置API。 其依赖于拓展SDK,做为地图
、位置
功能的补充。 其中提供的地图、定位能力依赖于第三方地图、定位、搜索SDK。支持高德地图|高德定位
、百度地图|百度定位
、两种组合情况使用,默认由原生地图实现,选择集成百度/高德,如果同时集成,使用最后初始化的那个。
使用步骤如下:
- 在 Xcode 项目的Podfile文件中添加对MapSDK的依赖:
// 如果您需要使用百度地图SDK,添加这个扩展SDK pod 'FinAppletBDMap' // 如果您需要使用高德地图SDK,添加这个扩展SDK pod 'FinAppletGDMap'
已复制代码
- 引入MapSDK的头文件:
// 同理,如果使用百度地图,则引入该头文件 #import <FinAppletBDMap/FinAppletBDMap.h> // 如果使用高德地图,则引入该头文件 #import <FinAppletGDMap/FinAppletGDMap.h>
已复制代码
- 注册MapSDK组件:
// 准备地图sdk初始化 // 如果使用百度地图,则使用这个api初始化 [FATBDMapComponent setBDMapAppKey:@"申请的key"] // 如果使用高德地图,则使用这个api初始化 [FATGDMapComponent setGDMapAppKey:@"申请的key"]
已复制代码
- 小程序中调用地图组件或者地图api。
# 2.27 为何FinClip 小程序 SDK 是动态库?可以交付静态库吗?
答:自从苹果支持第三方创建动态库之后,有很多第三方SDK都是动态库。使用动态库,可以将最终可执行文件体积缩小。为了使得App体积增长尽可能小,FinClip 小程序 SDK 一直对外提供的都是动态库。同时由于客户的App千差万别,使用的第三方库也不尽相同,使用静态库会在编译时或运行时遇到各种冲突问题。FinClip 研发团队资源和精力有限,所以暂时还不能同时维护静态库和动态库,所以现在正常迭代时只打包了动态库。
如果您一定坚持需要静态库,我们也可以特殊处理,单独打包静态库交付。我们也编写过Demo测试过使用FinClip静态库的Demo也能正常运行小程序。但是如果与宿主App发生冲突或者出现问题,无法保证及时处理。
另外,静态库现在只能手动集成,集成的步骤如下:
1. 添加SDK至工程
当然,如果你不需要用到FinAppletExt.framework中的api,那么,你也可以不添加FinAppletExt.framework 和 FinAppletExt.bundle。
注意
当手动引入FinAppletBDMap(百度地图)或FinAppletGDMap(高德地图)时,需手动将framework中的bundle资源文件也添加到工程中(FinAppletBDMap.bundle或FinAppletGDMap.bundle)。
2 修改工程配置
1)添加依赖的系统动态库:
2)Build Setting ->Other Linker Flags中添加-ObjC。
注意
当手动引入FinAppletBDMap(百度地图)或FinAppletGDMap(高德地图)时,嵌入类型默认为Do Not Embed(TARFGETS --- General --- Frameworks,Libraries,abd Embedded Content)。当手动引入高德地图时,需自行接入高德的AMap3DMap-NO-IDFA,AMapLocation-NO-IDFA,AMapSearch-NO-IDFA三个库,当手动引入百度地图时,需自行接入百度的BMKLocationKit,BaiduMapKit/Map,BaiduMapKit/Search三个库。
3 打开工程
双击xxxx.xcodeproj,打开工程。
4 配置archive脚本
SDK中包含x86_64架构,便于我们开发时用模拟器调试。但是x86_64架构的SDK,打包上传应用市场时会报错,所以配置一个打包时自动去除模拟器架构的脚本,可以让我们既可以用模拟器开发调试,又能正常提交应用市场。
当然,你也可以找我们要一个不包含模拟器的SDK。
脚本内容如下:
#!/bin/sh # Strip invalid architectures strip_invalid_archs() { binary="$1" echo "current binary ${binary}" # Get architectures for current file archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" stripped="" for arch in $archs; do if ! [[ "${ARCHS}" == *"$arch"* ]]; then if [ -f "$binary" ]; then # Strip non-valid architectures in-place lipo -remove "$arch" -output "$binary" "$binary" || exit 1 stripped="$stripped $arch" fi fi done if [[ "$stripped" ]]; then echo "Stripped $binary of architectures:$stripped" fi } APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}" # This script loops through the frameworks embedded in the application and # removes unused architectures. find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK do FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable) FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME" echo "Executable is $FRAMEWORK_EXECUTABLE_PATH" strip_invalid_archs "$FRAMEWORK_EXECUTABLE_PATH" done
已复制代码
# 2.28 小程序支持自定义更多面板吗?
答:支持。
通过实现FATAppletMoreMenuDelegate的 applet:(FATAppletInfo *)appletInfo didClickMoreBtnAtPath:(NSString *)path 代理方法实现弹出自定义更多面板。
/** 右上角胶囊中 【...】的点击事件,可在该事件中弹出自己设计的更多面板视图。 因此实现了该代理事件,就不会触发下面两个自定义菜单的事件 @param appletInfo 小程序信息 @path 小程序页面路径,示例:pages/index/index */ - (void)applet:(FATAppletInfo *)appletInfo didClickMoreBtnAtPath:(NSString *)path;
已复制代码
如果实现了自定义更多面板,但是想跳转到小程序的设置、关于、意见反馈等页面或者想实现转发功能,可以通过FATMoreMenuHelper提供的相关Api实现。
/// 触发转发事件,用来获取转发时用到的小程序信息, 获取到小程序信息后,会触发- (void)forwardAppletWithInfo:(NSDictionary *)contentInfo completion:(void (^)(FATExtensionCode, NSDictionary *))completion 这个回调 /// @param appletId 小程序id + (void)invokeForwardMenuAction:(NSString *)appletId; /// 更新小程序的收藏状态(需要设置当前的用户id,否则会更新失败) /// @param appletId 小程序id /// @param favorite 收藏状态 /// @param complete 结果回调,error为nil表示更新成功 + (void)updateApplet:(NSString *)appletId favoriteStatus:(BOOL)favorite withComplete:(void(^)(NSError *error,FATAppletInfo *appletInfo))complete; /// 打开小程序的意见反馈页面 /// @param appletId 小程序id + (void)goToFeedbackPage:(NSString *)appletId; /// 打开小程序的关于页面 /// @param appletId 小程序id + (void)goToAboutPage:(NSString *)appletId; /// 打开小程序的设置页面 /// @param appletId 小程序id + (void)goToSettingPage:(NSString *)appletId; /// 打开/关闭小程序的debug模式 如果config设置了enableAppletDebug为ture,执行打开/关闭debug模式操作会无效 /// @param appletId 小程序id /// @param enable 允许debug模式 + (void)setEnableAppletDebug:(NSString *)appletId enable:(BOOL)enable; /// 获取小程序是否打开debug模式 /// @param appletId 小程序id + (BOOL)isEnableAppletDebug:(NSString *)appletId; /// 获取小程序是否已收藏 /// @param appletId 小程序id + (BOOL)isAppletFavorite:(NSString *)appletId; /// 获取自定义菜单项的数据(需要小程序配合实现的菜单项,需要小程序提供额外调用参数) /// @param appletId 小程序id /// @param menuId 图标ID /// @param complete 结果回调 + (void)getMiniProgramTypeMenuData:(NSString *)appletId menuId:(NSString *)menuId complete:(void(^)(NSDictionary *result,FATAppletInfo *appletInfo))complete; /// 检测小程序是否实现自定义菜单功能 /// 其中onShareAppMessage事件受小程序是否调用了showShareMenu/hideShareMenu API影响 /// 若小程序调用了showShareMenu后调用该方法检测,则无论小程序是否实现onShareAppMessage事件,该事件对应的value为YES /// 若小程序调用了hideShareMenu后调用该方法检测,则无论小程序是否实现onShareAppMessage事件,该事件对应的value为NO /// @param appletId 小程序id /// @param menuIds 自定义图标ID数组 /// @param complete 结果回调,回调参数为NSArray,NSArray的元素为@{"eventName": ##小程序事件名##,"menuId": ##图标ID##, "value": ##事件是否实现#} + (void)checkMenus:(NSString *)appletId menuIds:(NSArray<NSString *> *)menuIds complete:(void(^)(NSArray *result))complete;
已复制代码
自定义更多面板示例代码:
// 在实现FATAppletMoreMenuDelegate的类中实现该代理方法,在该代理方法中可以使用自定义的菜单视图,最后必须返回YES - (BOOL)appletInfo:(FATAppletInfo *)appletInfo didClickMoreBtnAtPath:(NSString *)path { // 这里使用UIAlertController作为示例(用户可以自定义的视图) UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"更多菜单" message:@"自定义更多菜单" preferredStyle:UIAlertControllerStyleActionSheet]; UIAlertAction *forwardAction = [UIAlertAction actionWithTitle: @"转发" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { // 点击事件响应时,调用【+ (void)invokeForwardMenuAction:】方法,实现【转发】功能的调用 [FATMoreMenuHelper invokeForwardMenuAction:appletInfo.appId]; }]; [alertVC addAction:forwardAction]; UIAlertAction *feedbackAction = [UIAlertAction actionWithTitle:@"反馈与投诉" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { // 点击事件响应时,调用【+ (void)goToFeedbackPage:】方法,实现【反馈与投诉】页面的跳转 [FATMoreMenuHelper goToFeedbackPage:appletInfo.appId]; }]; [alertVC addAction:feedbackAction]; UIAlertAction *aboutAction = [UIAlertAction actionWithTitle:@"关于" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { // 点击事件响应时,调用【+ (void)goToAboutPage:】方法,实现【关于】页面的跳转 [FATMoreMenuHelper goToAboutPage:appletInfo.appId]; }]; [alertVC addAction:aboutAction]; UIAlertAction *settingAction = [UIAlertAction actionWithTitle:@"设置" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { // 点击事件响应时,调用【+ (void)goToSettingPage:】方法,实现【设置】页面的跳转 [FATMoreMenuHelper goToSettingPage:appletInfo.appId]; }]; [alertVC addAction:settingAction]; // 获取【debug模式】按钮的状态 BOOL enableDebug = [FATMoreMenuHelper isEnableAppletDebug:appletInfo.appId]; UIAlertAction *debugAction = [UIAlertAction actionWithTitle: enableDebug ? @"关闭debug模式" : @"打开debug模式" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { // 点击事件响应时,调用【+ (void)setEnableAppletDebug:enable:】方法,实现【debug模式】按钮的状态的设置 [FATMoreMenuHelper setEnableAppletDebug:appletInfo.appId enable:!enableDebug]; }]; [alertVC addAction:debugAction]; // 自定义的菜单按钮id NSArray *menuIds = @[ @"WXShareAPPFriends", @"WXShareAPPMoments", @"ShareSinaWeibo", @"ShareQQFriends" ]; // 调用【+ (void)checkMenus:menuIds:complete:】方法,检测传入的menuIds在小程序内是否实现 [FATMoreMenuHelper checkMenus:appletInfo.appId menuIds:menuIds complete:^(NSArray * _Nonnull result) { // 遍历检测结果 for (NSDictionary *dict in result) { NSString *title = dict[@"eventName"]; NSString *menuId = dict[@"menuId"]; BOOL value = [dict[@"value"] boolValue]; UIAlertAction *customAction = [UIAlertAction actionWithTitle:title style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { // 点击事件响应时,调用【+ (void)getMiniProgramTypeMenuData:menuId:complete:】方法,触发小程序调用自定义按钮方法 [FATMoreMenuHelper getMiniProgramTypeMenuData:appletInfo.appId menuId:menuId complete:^(NSDictionary * _Nonnull result, FATAppletInfo * _Nonnull appletInfo) { // 自定义菜单按钮点击事件回调,请在此处添加业务代码 }]; }]; // 设置按钮的点击状态 customAction.enabled = value; [alertVC addAction:customAction]; } [alertVC addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]]; // 展示自定义菜单 UIViewController *topVC = [[UIApplication sharedApplication] fin_topViewController]; [topVC presentViewController:alertVC animated:YES completion:nil]; }]; // 返回YES return YES; }
已复制代码
# 2.29 FinClip SDK支持批量更新小程序吗?
答:支持。
在SDK初始化完成后,调用【- (void)downloadApplets:apiServer:complete:】API可以实现预下载一个或多个小程序,即批量更新小程序功能。
示例代码:
/** @brief 批量更新小程序 @param appIds 小程序id数组 @param apiServer 服务器地址 @param complete 批量更新小程序回调 */ [[FATClient sharedClient] downloadApplets:##appIds## apiServer:##apiServer## complete:^(NSArray *results, FATError *error) { // 批量更新小程序回调 // results 批量更新小程序结果,是一个数组对象 // 其中元素为:@{@"appId": ##小程序id##, @"success": ##更新是否成功##, @"needUpdate": ##是否需要更新##} // 每次传入的小程序id,有可能本地已缓存了最新的版本,故有可能无需更新,此时needUpdate字段为false // error 错误,成功时为nil }];
已复制代码
# 2.30 FinClip SDK支持设置语言吗?如何设置?
FinClip iOS SDK 自2.40.0-alpha20230106v02 开始支持设置SDK的语言类型,这里的语言类型会影响SDK中(比如更多面板、关于、设置、投诉反馈等)公共UI中文字的语言。目前SDK内部仅支持简体中文 和 英文。设置其他语言字符串时,会显示为简体中文。iOS 2.42.7 版本开始,我们新增了 customLanguagePath 属性,用户可以通过配置该属性自定义国际化语言。
如何设置?
如果只需要设置中英文,FATConfig 中有一个 language 的配置项,初始化的时候设置该值即可。
示例代码:
FATStoreConfig *storeConfig = [[FATStoreConfig alloc] init]; storeConfig.sdkKey = @"这里填上的SDK Key"; storeConfig.sdkSecret = @"这里填上SDK secret"; storeConfig.apiServer = @"这里填上你们的服务器地址"; // 例如:https://api.finclip.com; storeConfig.apiPrefix = @"/api/v1/mop"; // 2.34.1以上可不配置apiPrefix FATConfig *config = [FATConfig configWithStoreConfigs:@[storeConfig]]; config.language = FATPreferredLanguageSimplifiedChinese;
已复制代码
如果需要设置其他国际化语言,则需要通过 customLanguagePath 属性自定义设置,优先级高于 language 属性。
以日语为例,在 iOS 开发工程创建国际化文件目录 jp.lproj
,并在目录下创建 Localizable.strings
文件,将我们FinApplet.framework
内部的 key 粘贴到这个文件下并进行翻译。
FATStoreConfig *storeConfig = [[FATStoreConfig alloc] init]; FATConfig *config = [FATConfig configWithStoreConfigs:@[storeConfig]]; // 直接将 jp.lproj 放在工程目录下(也就是 mainBundle 下),初始化方式如下 config.customLanguagePath = "jp.lproj"; // 或者,如果将 jp.lproj 文件存放在某个自定义 bundle 下,则需要带上相对路径 // config.customLanguagePath = "XXX.bundle/jp.lproj";
已复制代码
备注: 自定义国际化语言使用的 key 需要从 FinApplet.framework
中拿到,路径为: FinApplet.framework/FinApplet.bundle/zh-Hans.lproj/Localizable.strings
# 2.31 SDK中横竖屏的详细说明
目前SDK中的公共UI界面,比如 启动小程序时的loading页、关于、设置、投诉反馈页,以及小程序api打开的页面scancode、chooseLocation、openLocation等都是固定竖屏。
而小程序页面支持的方向,取决于小程序里app.json和page.json里设置的pageOrientation。
- pageOrienation为portrait,则表示该页面只支持Portrait。
- pageOrienation为landscape,则表示该页面支持LandscapeLeft和LandscapeRight。
- pageOrienation为auto,则表示该页面支持Portrait、LandscapeLeft、LandscapeRight。
SDK里的视图控制器可能是竖屏、也可能是横屏、也可能支持随设备横竖屏旋转,所以需要iOS工程配置,需要勾选Portrait、LandscapeLeft、LandscapeRight。
如果你的工程只支持竖屏
那么,你需要实现AppDelegate的如下方法。
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window { UIViewController *topVC = [application fat_topViewController]; Class class = NSClassFromString(@"FATUIViewController"); if ([topVC isKindOfClass:class]) { return UIInterfaceOrientationMaskAllButUpsideDown; } //2.45.3版本后可以用下面方法判断是否是finclip的视图控制器 <!-- [[FATClient sharedClient] fat_isFinclipViewController:topVC] --> return UIInterfaceOrientationMaskPortrait; }
已复制代码
如果你的工程只支持横屏
那么,你也需要实现AppDelegate的如下方法。
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window { UIViewController *topVC = [application fat_topViewController]; Class class = NSClassFromString(@"FATUIViewController"); if ([topVC isKindOfClass:class]) { return UIInterfaceOrientationMaskAllButUpsideDown; } //2.45.3版本后可以用下面方法判断是否是finclip的视图控制器 <!-- [[FATClient sharedClient] fat_isFinclipViewController:topVC] --> return UIInterfaceOrientationMaskLandscape; }
已复制代码
# 2.32 引入分享SDK会报错的处理。
如果遇到报错‘could not build module FinAppletWXExt\FinAppletShareExt’,这时候需要做这个处理,Build Settings --- Enable Modules(C and Objective-C) --- NO。
# 2.33 引入分享SDK后,分享面板没有展示出来
由于分享面板默认隐藏,所以在引入分享sdk后,还需要配置FATUIConfig的hideShareAppletMenu参数为False,展示分享面板。
# 2.34 小程序中的H5中的请求,body参数丢失,导致请求失败
答:出现H5中的body参数丢失问题,都是由于宿主app中拦截http/https协议导致的。比如:
// 使用NSURLProtocol 拦截会导致该问题 [HtmlURLProtocol HtmlURLProtocolRegisterScheme:@"http"]; [HtmlURLProtocol HtmlURLProtocolRegisterScheme:@"https"]; [NSURLProtocol registerClass:HtmlURLProtocol.class]; // 使用WKBrowsingContextController拦截也会导致该问题 [WKBrowsingContextController registerSchemeForCustomProtocol:@"https"]
已复制代码
该问题是由于:app 拦截http/https请求时,系统底层会将H5里的网络请求构造成request对象,但是构造成request对象的时候,并不会把body添加进request对象内。 所以,我们使用拦截到的request继续发起请求,服务器端收到的请求就会确实body中的业务参数,而导致请求失败。
该问题即使在原生app里拦截,然后app直接使用WKWebView也会遇到。这里有一个三方库解决了这个问题:https://github.com/karosLi/KKJSBridge
,我们FinClip SDK也参考该开源库的方案做了一个解决方案。
该方案的大致原理:
- 往HTML里注入一段js,在网络请求发起前,hook到网络请求,然后生成一个requestId。
- 调用原生的一个事件,将requestId和body内容发送至原生,原生将requestId和body匹配保存起来。
- HTML里原始网络请求的url后面拼接上requestId的参数。
- 原生在拦截http/https的事件里,通过NSURLRequest对象拿到url,然后取到requestId。
- 使用requestId,查找到对应的body,将body参数设置到NSURLRequest(一般是新建NSMutableURLRequest)上,发出请求。
- 删除存储的requestId 和body。
所以,在FinClip中解决方案如下: 1.初始化SDK时,设置是否允许hook H5中的网络请求,以及requestId的字段名。
FATConfig *config = [FATConfig configWithStoreConfigs:storeArrayM]; // 允许hook,才会注入hook处理的js config.enableH5AjaxHook = YES; // 设置拼接requestId的字段名,比如设置requestKey 为 FinClip-RequestId,那么拼接url 后,就会变成 https://www.exampleexample.com?FinClip-RequestId=xxxxxxx // 如果未设置该参数,则key为FinClipHookBridge-RequestId。 config.h5AjaxHookRequestKey = @"FinClip-RequestId";
已复制代码
2.设置小程序SDK配置的代理。
[FATClient sharedClient].configurationDelegate = self;
已复制代码
3.实现FATAppletConfigurationDelegate
中处理hook的body内容的代理方法。
#pragma mark - FATAppletConfigurationDelegate - (void)applet:(FATAppletInfo *)appletInfo hookRequestInfo:(NSDictionary *)requestInfo { NSLog(@"hookRequestInfo:%@", requestInfo); NSDictionary *data = requestInfo; NSString *requestId = data[@"requestId"]; // 这里 FATAjaxBodyManager 是我们demo app中随意常见的一个单例 FATAjaxBodyManager *bodyManager = [FATAjaxBodyManager manager]; bodyManager.bodyCacheDictionary[requestId] = data; }
已复制代码
4.在拦截http/https协议的处理类中设置body。(宿主app中的逻辑)
- (void)startLoading { NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy]; //给我们处理过的请求设置一个标识符, 防止无限循环, [NSURLProtocol setProperty:@YES forKey:FinClipNSURLProtocolKey inRequest:mutableReqeust]; NSString *requestId; if ([mutableReqeust.URL.absoluteString containsString:[self requestIdKey]]) { requestId = [self fetchRequestId:mutableReqeust.URL]; // 移除临时的请求id键值对 NSString *reqeustPair = [self fetchRequestIdPair:mutableReqeust.URL]; if (reqeustPair) { NSString *absString = [mutableReqeust.URL.absoluteString stringByReplacingOccurrencesOfString:reqeustPair withString:@""]; mutableReqeust.URL = [NSURL URLWithString:absString]; } } self.requestId = requestId; self.requestHTTPMethod = mutableReqeust.HTTPMethod; // 设置 body,针对有body的request类型,才做设置body NSArray<NSString *> *methods = @[@"POST"]; if (mutableReqeust.HTTPMethod.length > 0 && [methods containsObject:mutableReqeust.HTTPMethod]) { NSDictionary *bodyReqeust = [[FATAjaxBodyManager manager].bodyCacheDictionary objectForKey:requestId]; if (bodyReqeust) { // 从把缓存的 body 设置给 request [KKJSBridgeAjaxBodyHelper setBodyRequest:bodyReqeust toRequest:mutableReqeust]; } } NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil]; self.customTask = [session dataTaskWithRequest:mutableReqeust]; [self.customTask resume]; }
已复制代码
# 2.33 FinClip SDK支持设置自定义的省市区数据吗?如何设置?
FinClip iOS SDK 自2.43.1 开始支持设置SDK的省市区数据,用于指定一个自定义的文件路径,用于加载和展示区域数据。当设置此属性时,选择器将尝试从指定路径加载数据,可以是应用的沙盒目录中的路径,也可以是包含在应用Bundle中的文件名。
如何设置?
如果只需要设置中英文,FATConfig 中有一个 pickerRegionPath 的配置项,初始化的时候设置该值即可。
示例代码:
FATStoreConfig *storeConfig = [[FATStoreConfig alloc] init]; storeConfig.sdkKey = @"这里填上的SDK Key"; storeConfig.sdkSecret = @"这里填上SDK secret"; storeConfig.apiServer = @"这里填上你们的服务器地址"; // 例如:https://api.finclip.com; storeConfig.apiPrefix = @"/api/v1/mop"; // 2.34.1以上可不配置apiPrefix FATConfig *config = [FATConfig configWithStoreConfigs:@[storeConfig]]; config.language = @"customData.json";
已复制代码
备注: 如果需要传入沙盒内的文件,需要传入完整的路径。以下省市区数据的示例格式
postalCode:邮政编码 name:地区名 areaCode:区域代码
[ { "name": "北京市", "postalCode": "100000", "areaCode": "110000", "city": [ { "name": "北京市", "postalCode": "100000", "areaCode": "110100", "area": [ { "name": "东城区", "postalCode": "100010", "areaCode": "110101" }, { "name": "西城区", "postalCode": "100032", "areaCode": "110102" }, { "name": "朝阳区", "postalCode": "100020", "areaCode": "110105" }, { "name": "丰台区", "postalCode": "100071", "areaCode": "110106" }, { "name": "石景山区", "postalCode": "100043", "areaCode": "110107" }, { "name": "海淀区", "postalCode": "100089", "areaCode": "110108" }, { "name": "门头沟区", "postalCode": "102300", "areaCode": "110109" }, { "name": "房山区", "postalCode": "102488", "areaCode": "110111" }, { "name": "通州区", "postalCode": "101100", "areaCode": "110112" }, { "name": "顺义区", "postalCode": "101300", "areaCode": "110113" }, { "name": "昌平区", "postalCode": "102200", "areaCode": "110114" }, { "name": "大兴区", "postalCode": "102600", "areaCode": "110115" }, { "name": "怀柔区", "postalCode": "101400", "areaCode": "110116" }, { "name": "平谷区", "postalCode": "101200", "areaCode": "110117" }, { "name": "密云区", "postalCode": "101500", "areaCode": "110118" }, { "name": "延庆区", "postalCode": "102100", "areaCode": "110119" } ] } ] } ]
已复制代码
# 3. 调试方面
# 3.1 如何调试小程序?
在集成小程序SDK后,Xcode运行起小程序后(使用develop profile打包的应用也可以使用电脑Safari查看),可以打开电脑Safari,然后在工具栏 开发
中,选中运行的模拟器
或者 真机设备
,就可以选择小程序打开的页面列表,选中当前打开的页面,就可以审核页面元素、查看网络调用,以及一些log日志等。
# 3.2 如何开启vConsole?
如果需要调试小程序,目前有多种方式开启vconsole,从而可以看到小程序中的日志。 开关vconsole,要从SDK和小程序两个方面来说。
SDK方面 SDK里有两个地方影响vconsole的开启和关闭:
- 初始化配置项FATConfig中的appletDebugMode参数;
- 更多面板里的 【打开调试】和【关闭调试】按钮。
appletDebugMode是个枚举类型,目前一共有四个值:
- FATAppletDebugModeDefault:默认值,效果与微信的vConsole控制一致。
- FATAppletDebugModeEnable:强制所有小程序(所有版本)均开启vconsole,无法通过setEnableDebug和更多菜单里的调试菜单关闭。
- FATAppletDebugModeForbidden:强制所有小程序(所有版本)均关闭vconsole,无法通过setEnableDebug和更多菜单里的调试菜单开启。
- FATAppletDebugModeForbiddenRelease:强制所有小程序正式版均关闭vconsole,其他版本效果同FATAppletDebugModeDefault。
小程序方面
小程序里可以调用小程序api(ft.setEnableDebug
)来开启vconsole。
但是,如果config.appletDebugMode
设置为FATAppletDebugModeEnable
,则ft.setEnableDebug
接口不生效。
如果config.appletDebugMode
设置为FATAppletDebugModeForbidden
,则ft.setEnableDebug
接口也不生效。
注意
- 小程序的debug模式会持久化存储,即调用
ft.setEanbleDebug
开启vConsole后,下次打开同一个小程序也会开启vConsole。 - 同一个小程序的debug模式
configWithAppSecret:appKey:
未来会弃用,请尽早替换为configWithStoreConfigs
的方式构造FATConfig。- 自2.34.1开始,不再需要配置apiPrefix,内部已经在接口上配置好了apiPrefix。
最后,建议在app开发阶段,设置config.appletDebugMode
为FATAppletDebugModeEnable
;然后在App提交审核时,修改为FATAppletDebugModeDefault
。
因为设置为FATAppletDebugModeDefault
,正式版小程序 不会显示 【打开调试】和【关闭调试】按钮,但是依然可以通过api(ft.setEnableDebug
)来开启vconsole。
非正式版小程序,可以通过【打开调试】和ft.setEnableDebug
来开启vconsole。