fixUI
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
#import "KBSettingView.h"
|
||||
#import "Masonry.h"
|
||||
#import "KBAuthManager.h"
|
||||
#import "KBFullAccessManager.h"
|
||||
|
||||
static CGFloat KEYBOARDHEIGHT = 256 + 20;
|
||||
|
||||
@@ -34,6 +35,11 @@ static CGFloat KEYBOARDHEIGHT = 256 + 20;
|
||||
[self setupUI];
|
||||
// 指定 HUD 的承载视图(扩展里无法取到 App 的 KeyWindow)
|
||||
[KBHUD setContainerView:self.view];
|
||||
// 绑定完全访问管理器,便于统一感知和联动网络开关
|
||||
[[KBFullAccessManager shared] bindInputController:self];
|
||||
__unused id token = [[NSNotificationCenter defaultCenter] addObserverForName:KBFullAccessChangedNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(__unused NSNotification * _Nonnull note) {
|
||||
// 如需,可在此刷新与完全访问相关的 UI
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
|
||||
43
CustomKeyboard/Manager/KBFullAccessManager.h
Normal file
43
CustomKeyboard/Manager/KBFullAccessManager.h
Normal file
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// KBFullAccessManager.h
|
||||
// 统一封装:检测并管理键盘扩展的“允许完全访问”状态
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSInteger, KBFullAccessState) {
|
||||
KBFullAccessStateUnknown = 0, // 无法确定(降级处理为未开启)
|
||||
KBFullAccessStateDenied, // 未开启完全访问
|
||||
KBFullAccessStateGranted // 已开启完全访问
|
||||
};
|
||||
|
||||
/// 状态变更通知(仅扩展进程内广播)
|
||||
extern NSNotificationName const KBFullAccessChangedNotification;
|
||||
|
||||
/// 键盘扩展“完全访问”状态管理
|
||||
@interface KBFullAccessManager : NSObject
|
||||
|
||||
+ (instancetype)shared;
|
||||
|
||||
/// 绑定当前的 UIInputViewController(用于调用系统私有选择器 hasFullAccess;按字符串反射,避免编译期引用)
|
||||
- (void)bindInputController:(UIInputViewController *)ivc;
|
||||
|
||||
/// 当前状态(内部做缓存;如需强制刷新,调用 refresh)
|
||||
- (KBFullAccessState)currentState;
|
||||
|
||||
/// 便捷判断
|
||||
- (BOOL)hasFullAccess;
|
||||
|
||||
/// 立即刷新一次状态(若状态有变化会发送 KBFullAccessChangedNotification)
|
||||
- (void)refresh;
|
||||
|
||||
/// 若未开启,则在传入视图上展示引导弹层(使用现有的 KBFullAccessGuideView);返回是否已开启
|
||||
- (BOOL)ensureFullAccessOrGuideInView:(UIView *)parent;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
100
CustomKeyboard/Manager/KBFullAccessManager.m
Normal file
100
CustomKeyboard/Manager/KBFullAccessManager.m
Normal file
@@ -0,0 +1,100 @@
|
||||
//
|
||||
// KBFullAccessManager.m
|
||||
//
|
||||
// 统一封装“允许完全访问”检测:
|
||||
// 1) 首选:反射调用 UIInputViewController 的 hasFullAccess(避免直接引用私有 API 标识)
|
||||
// 2) 兜底:无法判断时返回 Unknown(上层可按需降级为 Denied 并提示)
|
||||
//
|
||||
|
||||
#import "KBFullAccessManager.h"
|
||||
#import <objc/message.h>
|
||||
#if __has_include("KBNetworkManager.h")
|
||||
#import "KBNetworkManager.h"
|
||||
#endif
|
||||
#if __has_include("KBKeyboardPermissionManager.h")
|
||||
#import "KBKeyboardPermissionManager.h"
|
||||
#endif
|
||||
|
||||
NSNotificationName const KBFullAccessChangedNotification = @"KBFullAccessChangedNotification";
|
||||
|
||||
@interface KBFullAccessManager ()
|
||||
@property (nonatomic, weak) UIInputViewController *ivc;
|
||||
@property (nonatomic, assign) KBFullAccessState state;
|
||||
@end
|
||||
|
||||
@implementation KBFullAccessManager
|
||||
|
||||
+ (instancetype)shared {
|
||||
static KBFullAccessManager *m; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ m = [KBFullAccessManager new]; });
|
||||
return m;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_state = KBFullAccessStateUnknown;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)bindInputController:(UIInputViewController *)ivc {
|
||||
self.ivc = ivc;
|
||||
[self refresh];
|
||||
}
|
||||
|
||||
- (KBFullAccessState)currentState { return _state; }
|
||||
|
||||
- (BOOL)hasFullAccess { return self.state == KBFullAccessStateGranted; }
|
||||
|
||||
- (void)refresh {
|
||||
KBFullAccessState newState = [self p_detectFullAccessState];
|
||||
if (newState != self.state) {
|
||||
self.state = newState;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:KBFullAccessChangedNotification object:nil];
|
||||
[self p_applySideEffects];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)ensureFullAccessOrGuideInView:(UIView *)parent {
|
||||
[self refresh];
|
||||
if (self.state == KBFullAccessStateGranted) return YES;
|
||||
#if __has_include("KBFullAccessGuideView.h")
|
||||
// 动态引入,避免主 App 编译引用
|
||||
Class guideCls = NSClassFromString(@"KBFullAccessGuideView");
|
||||
if (guideCls && [guideCls respondsToSelector:NSSelectorFromString(@"showInView:")]) {
|
||||
SEL sel = NSSelectorFromString(@"showInView:");
|
||||
((void (*)(id, SEL, UIView *))objc_msgSend)(guideCls, sel, parent);
|
||||
}
|
||||
#endif
|
||||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark - Detect
|
||||
|
||||
// 通过反射调用 hasFullAccess(若系统提供),否则返回 Unknown
|
||||
- (KBFullAccessState)p_detectFullAccessState {
|
||||
UIInputViewController *ivc = self.ivc;
|
||||
if (!ivc) return KBFullAccessStateUnknown;
|
||||
|
||||
SEL sel = NSSelectorFromString(@"hasFullAccess");
|
||||
if ([ivc respondsToSelector:sel]) {
|
||||
BOOL granted = ((BOOL (*)(id, SEL))objc_msgSend)(ivc, sel);
|
||||
return granted ? KBFullAccessStateGranted : KBFullAccessStateDenied;
|
||||
}
|
||||
// 无法判断时标记 Unknown(上层可按需处理为未开启)
|
||||
return KBFullAccessStateUnknown;
|
||||
}
|
||||
|
||||
#pragma mark - Side Effects
|
||||
|
||||
- (void)p_applySideEffects {
|
||||
#if __has_include("KBNetworkManager.h")
|
||||
// 根据完全访问状态切换网络总开关
|
||||
[KBNetworkManager shared].enabled = (self.state == KBFullAccessStateGranted);
|
||||
#endif
|
||||
#if __has_include("KBKeyboardPermissionManager.h")
|
||||
// 上报给主 App:记录最近一次“完全访问”状态(App 将据此决定是否展示引导页)
|
||||
[[KBKeyboardPermissionManager shared] reportFullAccessFromExtension:(self.state == KBFullAccessStateGranted)];
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -12,6 +12,7 @@
|
||||
#import "Masonry.h"
|
||||
#import <MBProgressHUD.h>
|
||||
#import "KBFullAccessGuideView.h"
|
||||
#import "KBFullAccessManager.h"
|
||||
|
||||
static NSString * const kKBFunctionTagCellId = @"KBFunctionTagCellId";
|
||||
|
||||
@@ -184,9 +185,8 @@ static NSString * const kKBFunctionTagCellId = @"KBFunctionTagCellId";
|
||||
NSURL *scheme = [NSURL URLWithString:[NSString stringWithFormat:@"kbkeyboard://login?src=functionView&index=%ld&title=%@", (long)indexPath.item, encodedTitle]];
|
||||
[ivc.extensionContext openURL:scheme completionHandler:^(BOOL ok2) {
|
||||
if (!ok2) {
|
||||
// 两条路都失败:大概率未开完全访问或宿主拦截。给出指引层。
|
||||
// [KBHUD showWithStatus:@"点击测试"];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{ [KBFullAccessGuideView showInView:self]; });
|
||||
// 两条路都失败:大概率未开完全访问或宿主拦截。统一交由 Manager 引导。
|
||||
dispatch_async(dispatch_get_main_queue(), ^{ [[KBFullAccessManager shared] ensureFullAccessOrGuideInView:self]; });
|
||||
}
|
||||
}];
|
||||
}];
|
||||
|
||||
@@ -31,3 +31,8 @@
|
||||
#ifndef KB_KEYCHAIN_ACCESS_GROUP
|
||||
#define KB_KEYCHAIN_ACCESS_GROUP @"TN6HHV45BB.com.keyBoardst.shared"
|
||||
#endif
|
||||
|
||||
// 键盘扩展的 Bundle Identifier(用于 App 侧检测是否已添加该键盘)
|
||||
#ifndef KB_KEYBOARD_EXTENSION_BUNDLE_ID
|
||||
#define KB_KEYBOARD_EXTENSION_BUNDLE_ID @"com.keyBoardst.CustomKeyboard"
|
||||
#endif
|
||||
|
||||
37
Shared/KBKeyboardPermissionManager.h
Normal file
37
Shared/KBKeyboardPermissionManager.h
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// KBKeyboardPermissionManager.h
|
||||
// 主 App/键盘扩展 共用的“键盘启用 + 完全访问”权限管理
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSInteger, KBFARecord) {
|
||||
KBFARecordUnknown = 0,
|
||||
KBFARecordDenied = 1,
|
||||
KBFARecordGranted = 2,
|
||||
};
|
||||
|
||||
/// 统一权限管理(App 与扩展均可使用)
|
||||
@interface KBKeyboardPermissionManager : NSObject
|
||||
|
||||
+ (instancetype)shared;
|
||||
|
||||
/// App 侧:是否已添加并启用了自定义键盘(通过遍历 activeInputModes 粗略判断)
|
||||
- (BOOL)isKeyboardEnabled;
|
||||
|
||||
/// 最后一次由扩展上报的“完全访问”状态(来源:扩展运行后写入共享钥匙串)
|
||||
- (KBFARecord)lastKnownFullAccess;
|
||||
|
||||
/// 扩展侧:上报“完全访问”状态(写入共享钥匙串,以便 App 读取)
|
||||
- (void)reportFullAccessFromExtension:(BOOL)granted;
|
||||
|
||||
/// App 侧:若未满足“已启用键盘 + 完全访问(或未知)”则展示引导页(KBPermissionViewController)
|
||||
- (void)presentPermissionIfNeededFrom:(UIViewController *)presenting;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
94
Shared/KBKeyboardPermissionManager.m
Normal file
94
Shared/KBKeyboardPermissionManager.m
Normal file
@@ -0,0 +1,94 @@
|
||||
//
|
||||
// KBKeyboardPermissionManager.m
|
||||
//
|
||||
|
||||
#import "KBKeyboardPermissionManager.h"
|
||||
#import <Security/Security.h>
|
||||
#import "KBConfig.h"
|
||||
|
||||
// Keychain 存储:记录上次扩展上报的“完全访问”状态
|
||||
static NSString * const kKBPermService = @"com.keyBoardst.perm";
|
||||
static NSString * const kKBPermAccount = @"full_access"; // 保存一个字节/数字:0/1/2
|
||||
|
||||
@implementation KBKeyboardPermissionManager
|
||||
|
||||
+ (instancetype)shared {
|
||||
static KBKeyboardPermissionManager *m; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ m = [KBKeyboardPermissionManager new]; });
|
||||
return m;
|
||||
}
|
||||
|
||||
#pragma mark - App side
|
||||
|
||||
- (BOOL)isKeyboardEnabled {
|
||||
// 与 AppDelegate 中同思路:遍历 activeInputModes,匹配自家扩展 bundle id
|
||||
for (UITextInputMode *mode in [UITextInputMode activeInputModes]) {
|
||||
NSString *identifier = nil;
|
||||
@try { identifier = [mode valueForKey:@"identifier"]; } @catch (__unused NSException *e) { identifier = nil; }
|
||||
if ([identifier isKindOfClass:NSString.class] && [identifier rangeOfString:KB_KEYBOARD_EXTENSION_BUNDLE_ID].location != NSNotFound) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (KBFARecord)lastKnownFullAccess {
|
||||
NSData *data = [self keychainRead];
|
||||
if (data.length == 0) return KBFARecordUnknown;
|
||||
uint8_t v = 0; [data getBytes:&v length:1];
|
||||
if (v > KBFARecordGranted) v = KBFARecordUnknown;
|
||||
return (KBFARecord)v;
|
||||
}
|
||||
|
||||
- (void)presentPermissionIfNeededFrom:(UIViewController *)presenting {
|
||||
BOOL enabled = [self isKeyboardEnabled];
|
||||
KBFARecord fa = [self lastKnownFullAccess];
|
||||
// 策略:
|
||||
// - 未启用键盘:一定引导;
|
||||
// - 已启用键盘:仅当明确知道“完全访问被拒绝”才引导;Unknown 不打扰(等待扩展上报)。
|
||||
BOOL needGuide = (!enabled) || (enabled && fa == KBFARecordDenied);
|
||||
if (!needGuide || !presenting) return;
|
||||
|
||||
Class cls = NSClassFromString(@"KBPermissionViewController");
|
||||
if (!cls) return; // 主 App 才存在该类
|
||||
UIViewController *guide = [cls new];
|
||||
guide.modalPresentationStyle = UIModalPresentationFullScreen;
|
||||
[presenting presentViewController:guide animated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - Extension side
|
||||
|
||||
- (void)reportFullAccessFromExtension:(BOOL)granted {
|
||||
uint8_t v = granted ? KBFARecordGranted : KBFARecordDenied;
|
||||
NSData *data = [NSData dataWithBytes:&v length:1];
|
||||
[self keychainWrite:data];
|
||||
}
|
||||
|
||||
#pragma mark - Keychain shared blob
|
||||
|
||||
- (NSMutableDictionary *)baseKCQuery {
|
||||
NSMutableDictionary *q = [@{ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
|
||||
(__bridge id)kSecAttrService: kKBPermService,
|
||||
(__bridge id)kSecAttrAccount: kKBPermAccount } mutableCopy];
|
||||
q[(__bridge id)kSecAttrAccessGroup] = KB_KEYCHAIN_ACCESS_GROUP;
|
||||
return q;
|
||||
}
|
||||
|
||||
- (BOOL)keychainWrite:(NSData *)data {
|
||||
NSMutableDictionary *query = [self baseKCQuery];
|
||||
SecItemDelete((__bridge CFDictionaryRef)query);
|
||||
query[(__bridge id)kSecValueData] = data ?: [NSData data];
|
||||
query[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
|
||||
OSStatus st = SecItemAdd((__bridge CFDictionaryRef)query, NULL);
|
||||
return (st == errSecSuccess);
|
||||
}
|
||||
|
||||
- (NSData *)keychainRead {
|
||||
NSMutableDictionary *query = [self baseKCQuery];
|
||||
query[(__bridge id)kSecReturnData] = @YES;
|
||||
query[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;
|
||||
CFTypeRef dataRef = NULL; OSStatus st = SecItemCopyMatching((__bridge CFDictionaryRef)query, &dataRef);
|
||||
if (st != errSecSuccess || !dataRef) return nil;
|
||||
return (__bridge_transfer NSData *)dataRef;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -9,6 +9,9 @@
|
||||
/* Begin PBXBuildFile section */
|
||||
043FBCD22EAF97630036AFE1 /* KBPermissionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04C6EAE12EAF940F0089C901 /* KBPermissionViewController.m */; };
|
||||
04A9FE0F2EB481100020DB6D /* KBHUD.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC97082EB31B14007BD342 /* KBHUD.m */; };
|
||||
04A9FE132EB4D0D20020DB6D /* KBFullAccessManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 04A9FE112EB4D0D20020DB6D /* KBFullAccessManager.m */; };
|
||||
04A9FE162EB873C80020DB6D /* UIViewController+Extension.m in Sources */ = {isa = PBXBuildFile; fileRef = 04A9FE152EB873C80020DB6D /* UIViewController+Extension.m */; };
|
||||
04A9FE172EB873C80020DB6D /* UIViewController+Extension.m in Sources */ = {isa = PBXBuildFile; fileRef = 04A9FE152EB873C80020DB6D /* UIViewController+Extension.m */; };
|
||||
04C6EABA2EAF86530089C901 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 04C6EAAE2EAF86530089C901 /* Assets.xcassets */; };
|
||||
04C6EABC2EAF86530089C901 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 04C6EAB12EAF86530089C901 /* LaunchScreen.storyboard */; };
|
||||
04C6EABD2EAF86530089C901 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 04C6EAB42EAF86530089C901 /* Main.storyboard */; };
|
||||
@@ -38,8 +41,6 @@
|
||||
04FC95F12EB339A7007BD342 /* LoginViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95F02EB339A7007BD342 /* LoginViewController.m */; };
|
||||
04FC95F42EB339C1007BD342 /* AppleSignInManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95F32EB339C1007BD342 /* AppleSignInManager.m */; };
|
||||
04FC96142EB34E00007BD342 /* KBLoginSheetViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC96122EB34E00007BD342 /* KBLoginSheetViewController.m */; };
|
||||
A1B2C4002EB4A0A100000003 /* KBAuthManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C4002EB4A0A100000002 /* KBAuthManager.m */; };
|
||||
A1B2C4002EB4A0A100000004 /* KBAuthManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C4002EB4A0A100000002 /* KBAuthManager.m */; };
|
||||
04FC97002EB30A00007BD342 /* KBGuideTopCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC96FF2EB30A00007BD342 /* KBGuideTopCell.m */; };
|
||||
04FC97032EB30A00007BD342 /* KBGuideKFCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC97022EB30A00007BD342 /* KBGuideKFCell.m */; };
|
||||
04FC97062EB30A00007BD342 /* KBGuideUserCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC97052EB30A00007BD342 /* KBGuideUserCell.m */; };
|
||||
@@ -50,6 +51,10 @@
|
||||
A1B2C3D42EB0A0A100000001 /* KBFunctionTagCell.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3D32EB0A0A100000001 /* KBFunctionTagCell.m */; };
|
||||
A1B2C3E22EB0C0A100000001 /* KBNetworkManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3E12EB0C0A100000001 /* KBNetworkManager.m */; };
|
||||
A1B2C3F42EB35A9900000001 /* KBFullAccessGuideView.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3F22EB35A9900000001 /* KBFullAccessGuideView.m */; };
|
||||
A1B2C4002EB4A0A100000003 /* KBAuthManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C4002EB4A0A100000002 /* KBAuthManager.m */; };
|
||||
A1B2C4002EB4A0A100000004 /* KBAuthManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C4002EB4A0A100000002 /* KBAuthManager.m */; };
|
||||
A1B2C4202EB4B7A100000001 /* KBKeyboardPermissionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C4222EB4B7A100000001 /* KBKeyboardPermissionManager.m */; };
|
||||
A1B2C4212EB4B7A100000001 /* KBKeyboardPermissionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C4222EB4B7A100000001 /* KBKeyboardPermissionManager.m */; };
|
||||
ECC9EE02174D86E8D792472F /* Pods_keyBoard.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 967065BB5230E43F293B3AF9 /* Pods_keyBoard.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@@ -78,6 +83,10 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
04A9FE102EB4D0D20020DB6D /* KBFullAccessManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBFullAccessManager.h; sourceTree = "<group>"; };
|
||||
04A9FE112EB4D0D20020DB6D /* KBFullAccessManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBFullAccessManager.m; sourceTree = "<group>"; };
|
||||
04A9FE142EB873C80020DB6D /* UIViewController+Extension.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIViewController+Extension.h"; sourceTree = "<group>"; };
|
||||
04A9FE152EB873C80020DB6D /* UIViewController+Extension.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+Extension.m"; sourceTree = "<group>"; };
|
||||
04C6EAAC2EAF86530089C901 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||
04C6EAAD2EAF86530089C901 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||
04C6EAAE2EAF86530089C901 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
@@ -151,8 +160,6 @@
|
||||
04FC970C2EB334F8007BD342 /* KBWebImageManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBWebImageManager.h; sourceTree = "<group>"; };
|
||||
04FC970D2EB334F8007BD342 /* KBWebImageManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBWebImageManager.m; sourceTree = "<group>"; };
|
||||
04FC98012EB36AAB007BD342 /* KBConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBConfig.h; sourceTree = "<group>"; };
|
||||
A1B2C4002EB4A0A100000001 /* KBAuthManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAuthManager.h; sourceTree = "<group>"; };
|
||||
A1B2C4002EB4A0A100000002 /* KBAuthManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAuthManager.m; sourceTree = "<group>"; };
|
||||
2C1092FB2B452F95B15D4263 /* Pods_CustomKeyboard.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_CustomKeyboard.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
51FE7C4C42C2255B3C1C4128 /* Pods-keyBoard.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-keyBoard.release.xcconfig"; path = "Target Support Files/Pods-keyBoard/Pods-keyBoard.release.xcconfig"; sourceTree = "<group>"; };
|
||||
727EC7532EAF848B00B36487 /* keyBoard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = keyBoard.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -163,6 +170,10 @@
|
||||
A1B2C3E12EB0C0A100000001 /* KBNetworkManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBNetworkManager.m; sourceTree = "<group>"; };
|
||||
A1B2C3F12EB35A9900000001 /* KBFullAccessGuideView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBFullAccessGuideView.h; sourceTree = "<group>"; };
|
||||
A1B2C3F22EB35A9900000001 /* KBFullAccessGuideView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBFullAccessGuideView.m; sourceTree = "<group>"; };
|
||||
A1B2C4002EB4A0A100000001 /* KBAuthManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAuthManager.h; sourceTree = "<group>"; };
|
||||
A1B2C4002EB4A0A100000002 /* KBAuthManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAuthManager.m; sourceTree = "<group>"; };
|
||||
A1B2C4222EB4B7A100000001 /* KBKeyboardPermissionManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBKeyboardPermissionManager.m; sourceTree = "<group>"; };
|
||||
A1B2C4232EB4B7A100000001 /* KBKeyboardPermissionManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBKeyboardPermissionManager.h; sourceTree = "<group>"; };
|
||||
B12EC429812407B9F0E67565 /* Pods-CustomKeyboard.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CustomKeyboard.release.xcconfig"; path = "Target Support Files/Pods-CustomKeyboard/Pods-CustomKeyboard.release.xcconfig"; sourceTree = "<group>"; };
|
||||
B8CA018AB878499327504AAD /* Pods-CustomKeyboard.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CustomKeyboard.debug.xcconfig"; path = "Target Support Files/Pods-CustomKeyboard/Pods-CustomKeyboard.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
F67DDBD716E4E616D8CC2C9C /* Pods-keyBoard.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-keyBoard.debug.xcconfig"; path = "Target Support Files/Pods-keyBoard/Pods-keyBoard.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
@@ -188,6 +199,15 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
04A9FE122EB4D0D20020DB6D /* Manager */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
04A9FE102EB4D0D20020DB6D /* KBFullAccessManager.h */,
|
||||
04A9FE112EB4D0D20020DB6D /* KBFullAccessManager.m */,
|
||||
);
|
||||
path = Manager;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
04C6EAB92EAF86530089C901 /* keyBoard */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -211,6 +231,7 @@
|
||||
04C6EAD72EAF870B0089C901 /* CustomKeyboard */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
04A9FE122EB4D0D20020DB6D /* Manager */,
|
||||
04FC95662EB0546C007BD342 /* Model */,
|
||||
04C6EADA2EAF8C7B0089C901 /* View */,
|
||||
A1B2C3E52EB0C0A100000001 /* Network */,
|
||||
@@ -469,6 +490,8 @@
|
||||
04FC970D2EB334F8007BD342 /* KBWebImageManager.m */,
|
||||
04FC97072EB31B14007BD342 /* KBHUD.h */,
|
||||
04FC97082EB31B14007BD342 /* KBHUD.m */,
|
||||
04A9FE142EB873C80020DB6D /* UIViewController+Extension.h */,
|
||||
04A9FE152EB873C80020DB6D /* UIViewController+Extension.m */,
|
||||
);
|
||||
path = Categories;
|
||||
sourceTree = "<group>";
|
||||
@@ -532,6 +555,8 @@
|
||||
04FC98012EB36AAB007BD342 /* KBConfig.h */,
|
||||
A1B2C4002EB4A0A100000001 /* KBAuthManager.h */,
|
||||
A1B2C4002EB4A0A100000002 /* KBAuthManager.m */,
|
||||
A1B2C4232EB4B7A100000001 /* KBKeyboardPermissionManager.h */,
|
||||
A1B2C4222EB4B7A100000001 /* KBKeyboardPermissionManager.m */,
|
||||
);
|
||||
path = Shared;
|
||||
sourceTree = "<group>";
|
||||
@@ -771,9 +796,12 @@
|
||||
04FC95B22EB0B2CC007BD342 /* KBSettingView.m in Sources */,
|
||||
04FC95702EB09516007BD342 /* KBFunctionView.m in Sources */,
|
||||
04FC956D2EB054B7007BD342 /* KBKeyboardView.m in Sources */,
|
||||
04A9FE172EB873C80020DB6D /* UIViewController+Extension.m in Sources */,
|
||||
04FC95672EB0546C007BD342 /* KBKey.m in Sources */,
|
||||
A1B2C3F42EB35A9900000001 /* KBFullAccessGuideView.m in Sources */,
|
||||
A1B2C4002EB4A0A100000003 /* KBAuthManager.m in Sources */,
|
||||
04A9FE132EB4D0D20020DB6D /* KBFullAccessManager.m in Sources */,
|
||||
A1B2C4202EB4B7A100000001 /* KBKeyboardPermissionManager.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -784,6 +812,7 @@
|
||||
04FC95E92EB23B67007BD342 /* KBNetworkManager.m in Sources */,
|
||||
04FC95D22EB1E7AE007BD342 /* MyVC.m in Sources */,
|
||||
043FBCD22EAF97630036AFE1 /* KBPermissionViewController.m in Sources */,
|
||||
04A9FE162EB873C80020DB6D /* UIViewController+Extension.m in Sources */,
|
||||
04C6EABE2EAF86530089C901 /* AppDelegate.m in Sources */,
|
||||
04FC95F12EB339A7007BD342 /* LoginViewController.m in Sources */,
|
||||
04FC96142EB34E00007BD342 /* KBLoginSheetViewController.m in Sources */,
|
||||
@@ -804,6 +833,7 @@
|
||||
04FC95F42EB339C1007BD342 /* AppleSignInManager.m in Sources */,
|
||||
04C6EAC12EAF86530089C901 /* ViewController.m in Sources */,
|
||||
A1B2C4002EB4A0A100000004 /* KBAuthManager.m in Sources */,
|
||||
A1B2C4212EB4B7A100000001 /* KBKeyboardPermissionManager.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -847,10 +877,10 @@
|
||||
DEVELOPMENT_TEAM = TN6HHV45BB;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GCC_PREFIX_HEADER = CustomKeyboard/PrefixHeader.pch;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
"KB_KEYCHAIN_ACCESS_GROUP=@\\\"$(AppIdentifierPrefix)com.keyBoardst.shared\\\"",
|
||||
);
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
"KB_KEYCHAIN_ACCESS_GROUP=@\\\"$(AppIdentifierPrefix)com.keyBoardst.shared\\\"",
|
||||
);
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = CustomKeyboard/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "我的输入法";
|
||||
@@ -880,10 +910,10 @@
|
||||
DEVELOPMENT_TEAM = TN6HHV45BB;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GCC_PREFIX_HEADER = CustomKeyboard/PrefixHeader.pch;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
"KB_KEYCHAIN_ACCESS_GROUP=@\\\"$(AppIdentifierPrefix)com.keyBoardst.shared\\\"",
|
||||
);
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
"KB_KEYCHAIN_ACCESS_GROUP=@\\\"$(AppIdentifierPrefix)com.keyBoardst.shared\\\"",
|
||||
);
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = CustomKeyboard/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "我的输入法";
|
||||
@@ -914,10 +944,10 @@
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = TN6HHV45BB;
|
||||
GCC_PREFIX_HEADER = keyBoard/KeyBoardPrefixHeader.pch;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
"KB_KEYCHAIN_ACCESS_GROUP=@\\\"$(AppIdentifierPrefix)com.keyBoardst.shared\\\"",
|
||||
);
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
"KB_KEYCHAIN_ACCESS_GROUP=@\\\"$(AppIdentifierPrefix)com.keyBoardst.shared\\\"",
|
||||
);
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = keyBoard/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "YOLO输入法";
|
||||
@@ -952,10 +982,10 @@
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = TN6HHV45BB;
|
||||
GCC_PREFIX_HEADER = keyBoard/KeyBoardPrefixHeader.pch;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
"KB_KEYCHAIN_ACCESS_GROUP=@\\\"$(AppIdentifierPrefix)com.keyBoardst.shared\\\"",
|
||||
);
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
"KB_KEYCHAIN_ACCESS_GROUP=@\\\"$(AppIdentifierPrefix)com.keyBoardst.shared\\\"",
|
||||
);
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = keyBoard/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "YOLO输入法";
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#import "LoginViewController.h"
|
||||
#import "KBLoginSheetViewController.h"
|
||||
#import "AppleSignInManager.h"
|
||||
#import <objc/message.h>
|
||||
|
||||
// 注意:用于判断系统已启用本输入法扩展的 bundle id 需与扩展 target 的
|
||||
// PRODUCT_BUNDLE_IDENTIFIER 完全一致。
|
||||
@@ -34,9 +35,23 @@ static NSString * const kKBKeyboardExtensionBundleId = @"com.keyBoardst.CustomKe
|
||||
/// 设置GroupID进行配置
|
||||
// buglyConfig.applicationGroupIdentifier = @"";
|
||||
[Bugly startWithAppId:BuglyId config:buglyConfig];
|
||||
/// 判断获取键盘权限
|
||||
/// 判断获取键盘权限(统一管理):
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self kb_presentPermissionIfNeeded];
|
||||
UIViewController *top = [self kb_topMostViewController];
|
||||
if (top) {
|
||||
Class mgrCls = NSClassFromString(@"KBKeyboardPermissionManager");
|
||||
if (mgrCls && [mgrCls respondsToSelector:@selector(shared)]) {
|
||||
id mgr = [mgrCls performSelector:@selector(shared)];
|
||||
if ([mgr respondsToSelector:@selector(presentPermissionIfNeededFrom:)]) {
|
||||
// 避免私有 API 静态链接,运行时调用
|
||||
void (*func)(id, SEL, UIViewController *) = (void (*)(id, SEL, UIViewController *))objc_msgSend;
|
||||
func(mgr, @selector(presentPermissionIfNeededFrom:), top);
|
||||
}
|
||||
} else {
|
||||
// 兜底走原有逻辑(仅判断是否启用键盘)
|
||||
[self kb_presentPermissionIfNeeded];
|
||||
}
|
||||
}
|
||||
});
|
||||
return YES;
|
||||
}
|
||||
|
||||
15
keyBoard/Class/Categories/UIViewController+Extension.h
Normal file
15
keyBoard/Class/Categories/UIViewController+Extension.h
Normal file
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// UIViewController+Extension.h
|
||||
// keyBoard
|
||||
//
|
||||
// Created by Mac on 2025/11/3.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface UIViewController (Extension)
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
12
keyBoard/Class/Categories/UIViewController+Extension.m
Normal file
12
keyBoard/Class/Categories/UIViewController+Extension.m
Normal file
@@ -0,0 +1,12 @@
|
||||
//
|
||||
// UIViewController+Extension.m
|
||||
// keyBoard
|
||||
//
|
||||
// Created by Mac on 2025/11/3.
|
||||
//
|
||||
|
||||
#import "UIViewController+Extension.h"
|
||||
|
||||
@implementation UIViewController (Extension)
|
||||
|
||||
@end
|
||||
@@ -35,8 +35,8 @@
|
||||
// KBGuideVC *vc = [[KBGuideVC alloc] init];
|
||||
// [self.navigationController pushViewController:vc animated:true];
|
||||
// [KBHUD showInfo:@"加载中..."];
|
||||
[KBHUD show];
|
||||
[KBHUD showAllowTapToDismiss:true];
|
||||
// [KBHUD show];
|
||||
// [KBHUD showAllowTapToDismiss:true];
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user