最近尝试开发了一个Keyboard Extension,主要功能是用于服务微信上的那些商家。遇到过一些坑点,mark一下,也希望能帮到遇到同样问题的你们。
首先得理解Extension的概念,这个很重要,很重要,很重要。好吧,总而言之,言而总之,它就是个扩展.....
HostApp、ContainApp、KeyboardExtension三者之间的关系得捋清楚。开发者不能单独创建扩展,你得创建一个App应用(ContainApp),然后在target里面新建扩展(KeyboardExtension)。但是,扩展是有自己的BundleID的,它可以在其他App(HostApp)中独立运行。
比如,你用微信打开App应用KeyboardDemo的自定义键盘keyboard,微信:HostApp KeyboardDemo:ContainApp keyboard:Extension。
好吧,废话了,接下来是我经历的坑点:
//程序员,都是从0开始的
0、cocoapods导入,正常导入就行。
1、自定义高度。这个坑了我99根头发:一定要在viewWillAppear方法中添加给view添加高度约束!!!!在viewDidLoad和updateViewConstraints中添加,会先跳到自定义高度,然后回到默认高度(226),最后又回到自定义高度,体验极差!
2、viewDidLoad方法中,self.view.window为nil,updateViewConstraints中才有值。
3、 UIApplication, window, UIInputViewController的获取方法:
+ (UIApplication *)getApplication {
UIScreen *screen = [UIScreen mainScreen];
UIWindow*window = [screen valueForKey:@"_preferredFocusedWindow"];
if(!window)return nil;
UIResponder*responder = window.nextResponder;
while(!responder || ![responder isMemberOfClass:[UIApplication class]]) {
responder = responder.nextResponder;
}
return(UIApplication*)responder;
}
UIInputViewController *inputVC = (UIInputViewController *)window.rootViewController.childViewControllers.firstObject;
4、跳到containApp:
UIApplication *app; 可用上面获取UIApplication
SEL sel = NSSelectorFromString(@"openURL:");
if([app respondsToSelector:sel]) {
[app performSelector:selwithObject:url];
}
吐槽下,这个试了N次,然并卵
// [self.extensionContext openURL:url completionHandler:^(BOOL success) {
// NSLog(@"%@", success ? @"打开成功" : @"打开失败");
// }];
5、实时获取剪切板的内容,我是通过定时器获取剪切板内容的,不能通过UIPasteboardChangedNotification等通知监听,毕竟不同应用。
6、直接跳过textfiled/textview 直接输出,直接在自己的发送方法中:
[self.textDocumentProxy insertText:text];
[self.textDocumentProxy deleteBackward];
[self.textDocumentProxy insertText:@"\n"];
7、针对微信发送图片,方法1、分享(搜狗 讯飞等)方法2、复制到剪切板(我用的是YYImage,系统剪切板不能直接识别 Y YImage,UIImage *systemImage = [UIImage imageWithCGImage:image.CGImage];),提示用户点击微信输入框粘贴
8、针对微信发送表情动图,我用原生UIActivityViewController分享Data和沙盒URL都只能得到第一帧,剪切板也类似,求大佬们推荐解决方法.
9、微信朋友圈防折叠推测:我测出2个因素:1、粘贴 , 2、文字重复率。
10、获取剪切板文字:
+ (void)getPasterBoardStrResultBlock:(void(^)(NSString*))resultBlock {
if(!resultBlock)return;
UIPasteboard *pasterBoard = [UIPasteboard generalPasteboard];
if(pasterBoard.string.length>0) resultBlock(pasterBoard.string);
//ios10之前,需要完全权限才能拿到pasterBoard,没有则提示开启完全权限
if(!pasterBoard) {
[TipsManager showTipsWithStr:@"您需要在设置->通用->键盘开启完全权限"];
}else{
resultBlock(nil);
}
}
11、判断完全权限
static BOOL hasFullAccess = NO;
+ (BOOL)isGetAllAccessGranted {
if (hasFullAccess) {
NSLog(@"打开了权限");
returnYES;
}else{
if(@available(iOS11.0, *)) {
UIScreen*screen = [UIScreenmainScreen];
UIWindow*window = [screenvalueForKey:@"_preferredFocusedWindow"];
UIInputViewController *inputVC = (UIInputViewController *)window.rootViewController.childViewControllers.firstObject;
if ([inputVC isKindOfClass:[UIInputViewController class]]) {
hasFullAccess= inputVC.hasFullAccess;
}
}else{
UIPasteboard *board = [UIPasteboard generalPasteboard];
if(@available(iOS10.0, *)) {
NSString*originStr = board.string;
board.string=@"test";
hasFullAccess= board.hasStrings;
board.string= originStr;
}else{
hasFullAccess= board ?YES:NO;
}
}
}
if (!hasFullAccess) {
[TipsManager showTipsWithStr:@"您需要在设置->通用->键盘开启完全权限"];
}
return hasFullAccess;
}
最后,再次跪求在微信发送图片和表情包更优雅方案!欢迎讨论