This commit is contained in:
2025-11-03 13:25:41 +08:00
parent ffea9d2022
commit c7021e382e
12 changed files with 384 additions and 27 deletions

View File

@@ -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
}];
}

View 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

View 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

View File

@@ -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]; });
}
}];
}];

View File

@@ -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

View 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

View 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

View File

@@ -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输入法";

View File

@@ -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;
}

View 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

View File

@@ -0,0 +1,12 @@
//
// UIViewController+Extension.m
// keyBoard
//
// Created by Mac on 2025/11/3.
//
#import "UIViewController+Extension.h"
@implementation UIViewController (Extension)
@end

View File

@@ -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];
}
/*