101 lines
3.2 KiB
Objective-C
101 lines
3.2 KiB
Objective-C
//
|
||
// 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
|