处理上架的问题
1:处理了openurl 拉起问题 2:去掉了http 3 隐私等等
This commit is contained in:
9
.gitignore
vendored
9
.gitignore
vendored
@@ -1 +1,10 @@
|
|||||||
|
# Xcode / build artifacts
|
||||||
|
_DerivedData/
|
||||||
|
DerivedData/
|
||||||
|
*.xcresult/
|
||||||
|
xcuserdata/
|
||||||
|
|
||||||
|
# SwiftPM artifacts
|
||||||
_spm/
|
_spm/
|
||||||
|
_SourcePackages/
|
||||||
|
.swiftpm/
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
#import "KBChatMessage.h"
|
#import "KBChatMessage.h"
|
||||||
#import "KBChatPanelView.h"
|
#import "KBChatPanelView.h"
|
||||||
#import "KBFullAccessManager.h"
|
#import "KBFullAccessManager.h"
|
||||||
#import "KBHostAppLauncher.h"
|
#import "../Utils/KBExtensionAppLauncher.h"
|
||||||
#import "KBInputBufferManager.h"
|
#import "KBInputBufferManager.h"
|
||||||
#import "KBNetworkManager.h"
|
#import "KBNetworkManager.h"
|
||||||
#import "KBVM.h"
|
#import "KBVM.h"
|
||||||
@@ -118,7 +118,9 @@ static const NSUInteger kKBChatMessageLimit = 6;
|
|||||||
if (text.length == 0) {
|
if (text.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
NSLog(@"[KB] 发送消息: %@", text);
|
#if DEBUG
|
||||||
|
NSLog(@"[KB] 发送消息 len=%lu", (unsigned long)text.length);
|
||||||
|
#endif
|
||||||
|
|
||||||
KBChatMessage *outgoing = [KBChatMessage userMessageWithText:text];
|
KBChatMessage *outgoing = [KBChatMessage userMessageWithText:text];
|
||||||
outgoing.avatarURL = [self kb_sharedUserAvatarURL];
|
outgoing.avatarURL = [self kb_sharedUserAvatarURL];
|
||||||
@@ -702,11 +704,21 @@ static const NSUInteger kKBChatMessageLimit = 6;
|
|||||||
[NSString stringWithFormat:@"%@://recharge?src=keyboard&vipType=svip",
|
[NSString stringWithFormat:@"%@://recharge?src=keyboard&vipType=svip",
|
||||||
KB_APP_SCHEME];
|
KB_APP_SCHEME];
|
||||||
NSURL *scheme = [NSURL URLWithString:urlString];
|
NSURL *scheme = [NSURL URLWithString:urlString];
|
||||||
BOOL success = [KBHostAppLauncher openHostAppURL:scheme
|
NSString *ulString = [NSString stringWithFormat:@"%@?src=keyboard&vipType=svip", KB_UL_RECHARGE];
|
||||||
fromResponder:self.view];
|
NSURL *ul = [NSURL URLWithString:ulString];
|
||||||
if (!success) {
|
__weak typeof(self) weakSelf = self;
|
||||||
[KBHUD showInfo:KBLocalized(@"Please open the App to finish purchase")];
|
[KBExtensionAppLauncher openPrimaryURL:ul
|
||||||
}
|
fallbackURL:scheme
|
||||||
|
usingInputController:self
|
||||||
|
source:(self.view ?: (UIResponder *)weakSelf)
|
||||||
|
completion:^(BOOL success) {
|
||||||
|
if (success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[KBHUD showInfo:KBLocalized(@"Please open the App to finish purchase")];
|
||||||
|
});
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
#import "KBBackspaceUndoManager.h"
|
#import "KBBackspaceUndoManager.h"
|
||||||
#import "KBFullAccessManager.h"
|
#import "KBFullAccessManager.h"
|
||||||
#import "KBFunctionView.h"
|
#import "KBFunctionView.h"
|
||||||
#import "KBHostAppLauncher.h"
|
#import "../Utils/KBExtensionAppLauncher.h"
|
||||||
#import "KBInputBufferManager.h"
|
#import "KBInputBufferManager.h"
|
||||||
#import "KBKey.h"
|
#import "KBKey.h"
|
||||||
#import "KBKeyboardSubscriptionProduct.h"
|
#import "KBKeyboardSubscriptionProduct.h"
|
||||||
@@ -766,11 +766,15 @@ static NSString *KBFormatMB(uint64_t bytes) {
|
|||||||
// 2) 权限没问题,再判断是否登录:未登录 -> 直接拉起主 App,由主 App
|
// 2) 权限没问题,再判断是否登录:未登录 -> 直接拉起主 App,由主 App
|
||||||
// 负责完成登录
|
// 负责完成登录
|
||||||
if (!KBAuthManager.shared.isLoggedIn) {
|
if (!KBAuthManager.shared.isLoggedIn) {
|
||||||
NSString *schemeStr =
|
NSURL *ul = [NSURL URLWithString:[NSString stringWithFormat:@"%@?src=keyboard", KB_UL_LOGIN]];
|
||||||
[NSString stringWithFormat:@"%@://login?src=keyboard", KB_APP_SCHEME];
|
NSURL *scheme =
|
||||||
NSURL *scheme = [NSURL URLWithString:schemeStr];
|
[NSURL URLWithString:[NSString stringWithFormat:@"%@://login?src=keyboard", KB_APP_SCHEME]];
|
||||||
// 从当前视图作为起点,通过响应链找到 UIApplication 再调起主 App
|
__weak typeof(self) weakSelf = self;
|
||||||
BOOL ok = [KBHostAppLauncher openHostAppURL:scheme fromResponder:self.view];
|
[KBExtensionAppLauncher openPrimaryURL:ul
|
||||||
|
fallbackURL:scheme
|
||||||
|
usingInputController:self
|
||||||
|
source:(self.view ?: (UIResponder *)weakSelf)
|
||||||
|
completion:nil];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[[KBMaiPointReporter sharedReporter]
|
[[KBMaiPointReporter sharedReporter]
|
||||||
@@ -999,11 +1003,15 @@ static NSString *KBFormatMB(uint64_t bytes) {
|
|||||||
extra:@{@"action" : @"login_or_recharge"}
|
extra:@{@"action" : @"login_or_recharge"}
|
||||||
completion:nil];
|
completion:nil];
|
||||||
if (!KBAuthManager.shared.isLoggedIn) {
|
if (!KBAuthManager.shared.isLoggedIn) {
|
||||||
NSString *schemeStr =
|
NSURL *ul = [NSURL URLWithString:[NSString stringWithFormat:@"%@?src=keyboard", KB_UL_LOGIN]];
|
||||||
[NSString stringWithFormat:@"%@://login?src=keyboard", KB_APP_SCHEME];
|
NSURL *scheme =
|
||||||
NSURL *scheme = [NSURL URLWithString:schemeStr];
|
[NSURL URLWithString:[NSString stringWithFormat:@"%@://login?src=keyboard", KB_APP_SCHEME]];
|
||||||
// 从当前视图作为起点,通过响应链找到 UIApplication 再调起主 App
|
__weak typeof(self) weakSelf = self;
|
||||||
BOOL ok = [KBHostAppLauncher openHostAppURL:scheme fromResponder:self.view];
|
[KBExtensionAppLauncher openPrimaryURL:ul
|
||||||
|
fallbackURL:scheme
|
||||||
|
usingInputController:self
|
||||||
|
source:(self.view ?: (UIResponder *)weakSelf)
|
||||||
|
completion:nil];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
NSString *schemeStr =
|
NSString *schemeStr =
|
||||||
@@ -1013,13 +1021,20 @@ static NSString *KBFormatMB(uint64_t bytes) {
|
|||||||
// if (!ul && !scheme) { return; }
|
// if (!ul && !scheme) { return; }
|
||||||
//
|
//
|
||||||
// 从当前视图作为起点,通过响应链找到 UIApplication 再调起主 App
|
// 从当前视图作为起点,通过响应链找到 UIApplication 再调起主 App
|
||||||
BOOL ok = [KBHostAppLauncher openHostAppURL:scheme fromResponder:self.view];
|
__weak typeof(self) weakSelf = self;
|
||||||
|
NSURL *ul = [NSURL URLWithString:[NSString stringWithFormat:@"%@?src=keyboard", KB_UL_RECHARGE]];
|
||||||
if (!ok) {
|
[KBExtensionAppLauncher openPrimaryURL:ul
|
||||||
// 失败兜底:给个文案提示
|
fallbackURL:scheme
|
||||||
// 比如:请回到桌面手动打开 XXX App 进行设置/充值
|
usingInputController:self
|
||||||
[KBHUD showInfo:@"请回到桌面手动打开App进行充值"];
|
source:(self.view ?: (UIResponder *)weakSelf)
|
||||||
}
|
completion:^(BOOL success) {
|
||||||
|
if (success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[KBHUD showInfo:@"当前应用不允许键盘直接唤起App,请回到桌面手动打开App进行充值"];
|
||||||
|
});
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)functionViewDidRequestSubscription:(KBFunctionView *)functionView {
|
- (void)functionViewDidRequestSubscription:(KBFunctionView *)functionView {
|
||||||
@@ -1672,11 +1687,20 @@ static NSString *KBFormatMB(uint64_t bytes) {
|
|||||||
[NSString stringWithFormat:@"%@://recharge?src=keyboard&vipType=svip",
|
[NSString stringWithFormat:@"%@://recharge?src=keyboard&vipType=svip",
|
||||||
KB_APP_SCHEME];
|
KB_APP_SCHEME];
|
||||||
NSURL *scheme = [NSURL URLWithString:urlString];
|
NSURL *scheme = [NSURL URLWithString:urlString];
|
||||||
BOOL success = [KBHostAppLauncher openHostAppURL:scheme
|
NSURL *ul = [NSURL URLWithString:[NSString stringWithFormat:@"%@?src=keyboard&vipType=svip", KB_UL_RECHARGE]];
|
||||||
fromResponder:self.view];
|
__weak typeof(self) weakSelf = self;
|
||||||
if (!success) {
|
[KBExtensionAppLauncher openPrimaryURL:ul
|
||||||
[KBHUD showInfo:KBLocalized(@"Please open the App to finish purchase")];
|
fallbackURL:scheme
|
||||||
}
|
usingInputController:self
|
||||||
|
source:(self.view ?: (UIResponder *)weakSelf)
|
||||||
|
completion:^(BOOL success) {
|
||||||
|
if (success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[KBHUD showInfo:KBLocalized(@"Please open the App to finish purchase")];
|
||||||
|
});
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - lazy
|
#pragma mark - lazy
|
||||||
@@ -1753,11 +1777,21 @@ static NSString *KBFormatMB(uint64_t bytes) {
|
|||||||
NSString *urlString = [NSString
|
NSString *urlString = [NSString
|
||||||
stringWithFormat:@"%@://recharge?src=keyboard&%@", KB_APP_SCHEME, query];
|
stringWithFormat:@"%@://recharge?src=keyboard&%@", KB_APP_SCHEME, query];
|
||||||
NSURL *scheme = [NSURL URLWithString:urlString];
|
NSURL *scheme = [NSURL URLWithString:urlString];
|
||||||
BOOL success = [KBHostAppLauncher openHostAppURL:scheme
|
NSString *ulString = [NSString stringWithFormat:@"%@?src=keyboard&%@", KB_UL_RECHARGE, query];
|
||||||
fromResponder:self.view];
|
NSURL *ul = [NSURL URLWithString:ulString];
|
||||||
if (!success) {
|
__weak typeof(self) weakSelf = self;
|
||||||
[KBHUD showInfo:KBLocalized(@"Please open the App to finish purchase")];
|
[KBExtensionAppLauncher openPrimaryURL:ul
|
||||||
}
|
fallbackURL:scheme
|
||||||
|
usingInputController:self
|
||||||
|
source:(self.view ?: (UIResponder *)weakSelf)
|
||||||
|
completion:^(BOOL success) {
|
||||||
|
if (success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[KBHUD showInfo:KBLocalized(@"Please open the App to finish purchase")];
|
||||||
|
});
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSString *)kb_urlEncodedString:(NSString *)value {
|
+ (NSString *)kb_urlEncodedString:(NSString *)value {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
#import "KBChatPanelView.h"
|
#import "KBChatPanelView.h"
|
||||||
#import "KBFunctionView.h"
|
#import "KBFunctionView.h"
|
||||||
#import "KBFullAccessManager.h"
|
#import "KBFullAccessManager.h"
|
||||||
#import "KBHostAppLauncher.h"
|
#import "../Utils/KBExtensionAppLauncher.h"
|
||||||
#import "KBInputBufferManager.h"
|
#import "KBInputBufferManager.h"
|
||||||
#import "KBKey.h"
|
#import "KBKey.h"
|
||||||
#import "KBKeyBoardMainView.h"
|
#import "KBKeyBoardMainView.h"
|
||||||
@@ -55,13 +55,22 @@
|
|||||||
#endif
|
#endif
|
||||||
if (mode == KBKeyboardPanelModeFunction && !islogin) {
|
if (mode == KBKeyboardPanelModeFunction && !islogin) {
|
||||||
[KBHUD showInfo:KBLocalized(@"请先登录后使用AI功能")];
|
[KBHUD showInfo:KBLocalized(@"请先登录后使用AI功能")];
|
||||||
NSString *schemeStr =
|
NSURL *ul = [NSURL URLWithString:[NSString stringWithFormat:@"%@?src=keyboard", KB_UL_LOGIN]];
|
||||||
[NSString stringWithFormat:@"%@://login?src=keyboard", KB_APP_SCHEME];
|
NSURL *scheme =
|
||||||
NSURL *scheme = [NSURL URLWithString:schemeStr];
|
[NSURL URLWithString:[NSString stringWithFormat:@"%@://login?src=keyboard", KB_APP_SCHEME]];
|
||||||
BOOL ok = [KBHostAppLauncher openHostAppURL:scheme fromResponder:self.view];
|
__weak typeof(self) weakSelf = self;
|
||||||
if (!ok) {
|
[KBExtensionAppLauncher openPrimaryURL:ul
|
||||||
[KBHUD showInfo:KBLocalized(@"请回到桌面手动打开App登录")];
|
fallbackURL:scheme
|
||||||
}
|
usingInputController:self
|
||||||
|
source:(self.view ?: (UIResponder *)weakSelf)
|
||||||
|
completion:^(BOOL success) {
|
||||||
|
if (success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[KBHUD showInfo:KBLocalized(@"请回到桌面手动打开App登录")];
|
||||||
|
});
|
||||||
|
}];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -617,24 +626,33 @@
|
|||||||
extra:@{@"action" : @"login_or_recharge"}
|
extra:@{@"action" : @"login_or_recharge"}
|
||||||
completion:nil];
|
completion:nil];
|
||||||
if (!KBAuthManager.shared.isLoggedIn) {
|
if (!KBAuthManager.shared.isLoggedIn) {
|
||||||
NSString *schemeStr =
|
NSURL *ul = [NSURL URLWithString:[NSString stringWithFormat:@"%@?src=keyboard", KB_UL_LOGIN]];
|
||||||
[NSString stringWithFormat:@"%@://login?src=keyboard", KB_APP_SCHEME];
|
NSURL *scheme =
|
||||||
NSURL *scheme = [NSURL URLWithString:schemeStr];
|
[NSURL URLWithString:[NSString stringWithFormat:@"%@://login?src=keyboard", KB_APP_SCHEME]];
|
||||||
// 从当前视图作为起点,通过响应链找到 UIApplication 再调起主 App
|
__weak typeof(self) weakSelf = self;
|
||||||
BOOL ok = [KBHostAppLauncher openHostAppURL:scheme fromResponder:self.view];
|
[KBExtensionAppLauncher openPrimaryURL:ul
|
||||||
|
fallbackURL:scheme
|
||||||
|
usingInputController:self
|
||||||
|
source:(self.view ?: (UIResponder *)weakSelf)
|
||||||
|
completion:nil];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
NSString *schemeStr =
|
NSURL *ul = [NSURL URLWithString:[NSString stringWithFormat:@"%@?src=keyboard", KB_UL_RECHARGE]];
|
||||||
[NSString stringWithFormat:@"%@://recharge?src=keyboard", KB_APP_SCHEME];
|
NSURL *scheme =
|
||||||
NSURL *scheme = [NSURL URLWithString:schemeStr];
|
[NSURL URLWithString:[NSString stringWithFormat:@"%@://recharge?src=keyboard", KB_APP_SCHEME]];
|
||||||
// 从当前视图作为起点,通过响应链找到 UIApplication 再调起主 App
|
__weak typeof(self) weakSelf = self;
|
||||||
BOOL ok = [KBHostAppLauncher openHostAppURL:scheme fromResponder:self.view];
|
[KBExtensionAppLauncher openPrimaryURL:ul
|
||||||
|
fallbackURL:scheme
|
||||||
if (!ok) {
|
usingInputController:self
|
||||||
// 失败兜底:给个文案提示
|
source:(self.view ?: (UIResponder *)weakSelf)
|
||||||
// 比如:请回到桌面手动打开 XXX App 进行设置/充值
|
completion:^(BOOL success) {
|
||||||
[KBHUD showInfo:@"请回到桌面手动打开App进行充值"];
|
if (success) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[KBHUD showInfo:@"当前应用不允许键盘直接唤起App,请回到桌面手动打开App进行充值"];
|
||||||
|
});
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)functionViewDidRequestSubscription:(KBFunctionView *)functionView {
|
- (void)functionViewDidRequestSubscription:(KBFunctionView *)functionView {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
#import "KBAuthManager.h"
|
#import "KBAuthManager.h"
|
||||||
#import "KBFullAccessManager.h"
|
#import "KBFullAccessManager.h"
|
||||||
#import "KBHostAppLauncher.h"
|
#import "../Utils/KBExtensionAppLauncher.h"
|
||||||
#import "KBKeyboardSubscriptionProduct.h"
|
#import "KBKeyboardSubscriptionProduct.h"
|
||||||
#import "KBKeyboardSubscriptionView.h"
|
#import "KBKeyboardSubscriptionView.h"
|
||||||
|
|
||||||
@@ -26,11 +26,15 @@
|
|||||||
// 点击充值要先判断是否登录
|
// 点击充值要先判断是否登录
|
||||||
// 2) 权限没问题,再判断是否登录:未登录 -> 直接拉起主 App,由主 App 负责完成登录
|
// 2) 权限没问题,再判断是否登录:未登录 -> 直接拉起主 App,由主 App 负责完成登录
|
||||||
if (!KBAuthManager.shared.isLoggedIn) {
|
if (!KBAuthManager.shared.isLoggedIn) {
|
||||||
NSString *schemeStr =
|
NSURL *ul = [NSURL URLWithString:[NSString stringWithFormat:@"%@?src=keyboard", KB_UL_LOGIN]];
|
||||||
[NSString stringWithFormat:@"%@://login?src=keyboard", KB_APP_SCHEME];
|
NSURL *scheme =
|
||||||
NSURL *scheme = [NSURL URLWithString:schemeStr];
|
[NSURL URLWithString:[NSString stringWithFormat:@"%@://login?src=keyboard", KB_APP_SCHEME]];
|
||||||
// 从当前视图作为起点,通过响应链找到 UIApplication 再调起主 App
|
__weak typeof(self) weakSelf = self;
|
||||||
BOOL ok = [KBHostAppLauncher openHostAppURL:scheme fromResponder:self.view];
|
[KBExtensionAppLauncher openPrimaryURL:ul
|
||||||
|
fallbackURL:scheme
|
||||||
|
usingInputController:self
|
||||||
|
source:(self.view ?: (UIResponder *)weakSelf)
|
||||||
|
completion:nil];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self kb_setPanelMode:KBKeyboardPanelModeSubscription animated:YES];
|
[self kb_setPanelMode:KBKeyboardPanelModeSubscription animated:YES];
|
||||||
@@ -96,10 +100,21 @@
|
|||||||
NSString *urlString = [NSString
|
NSString *urlString = [NSString
|
||||||
stringWithFormat:@"%@://recharge?src=keyboard&%@", KB_APP_SCHEME, query];
|
stringWithFormat:@"%@://recharge?src=keyboard&%@", KB_APP_SCHEME, query];
|
||||||
NSURL *scheme = [NSURL URLWithString:urlString];
|
NSURL *scheme = [NSURL URLWithString:urlString];
|
||||||
BOOL success = [KBHostAppLauncher openHostAppURL:scheme fromResponder:self.view];
|
NSString *ulString = [NSString stringWithFormat:@"%@?src=keyboard&%@", KB_UL_RECHARGE, query];
|
||||||
if (!success) {
|
NSURL *ul = [NSURL URLWithString:ulString];
|
||||||
[KBHUD showInfo:KBLocalized(@"Please open the App to finish purchase")];
|
__weak typeof(self) weakSelf = self;
|
||||||
}
|
[KBExtensionAppLauncher openPrimaryURL:ul
|
||||||
|
fallbackURL:scheme
|
||||||
|
usingInputController:self
|
||||||
|
source:(self.view ?: (UIResponder *)weakSelf)
|
||||||
|
completion:^(BOOL success) {
|
||||||
|
if (success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[KBHUD showInfo:KBLocalized(@"Please open the App to finish purchase")];
|
||||||
|
});
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSString *)kb_urlEncodedString:(NSString *)value {
|
+ (NSString *)kb_urlEncodedString:(NSString *)value {
|
||||||
|
|||||||
@@ -2,12 +2,11 @@
|
|||||||
// KBFullAccessManager.m
|
// KBFullAccessManager.m
|
||||||
//
|
//
|
||||||
// 统一封装“允许完全访问”检测:
|
// 统一封装“允许完全访问”检测:
|
||||||
// 1) 首选:反射调用 UIInputViewController 的 hasFullAccess(避免直接引用私有 API 标识)
|
// 1) 直接使用 UIInputViewController.hasFullAccess(公开 API)
|
||||||
// 2) 兜底:无法判断时返回 Unknown(上层可按需降级为 Denied 并提示)
|
// 2) 兜底:无法判断时返回 Unknown(上层可按需降级为 Denied 并提示)
|
||||||
//
|
//
|
||||||
|
|
||||||
#import "KBFullAccessManager.h"
|
#import "KBFullAccessManager.h"
|
||||||
#import <objc/message.h>
|
|
||||||
#if __has_include("KBNetworkManager.h")
|
#if __has_include("KBNetworkManager.h")
|
||||||
#import "KBNetworkManager.h"
|
#import "KBNetworkManager.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -62,7 +61,10 @@ NSNotificationName const KBFullAccessChangedNotification = @"KBFullAccessChanged
|
|||||||
Class guideCls = NSClassFromString(@"KBFullAccessGuideView");
|
Class guideCls = NSClassFromString(@"KBFullAccessGuideView");
|
||||||
if (guideCls && [guideCls respondsToSelector:NSSelectorFromString(@"showInView:")]) {
|
if (guideCls && [guideCls respondsToSelector:NSSelectorFromString(@"showInView:")]) {
|
||||||
SEL sel = NSSelectorFromString(@"showInView:");
|
SEL sel = NSSelectorFromString(@"showInView:");
|
||||||
((void (*)(id, SEL, UIView *))objc_msgSend)(guideCls, sel, parent);
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||||
|
[guideCls performSelector:sel withObject:parent];
|
||||||
|
#pragma clang diagnostic pop
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return NO;
|
return NO;
|
||||||
@@ -74,13 +76,9 @@ NSNotificationName const KBFullAccessChangedNotification = @"KBFullAccessChanged
|
|||||||
- (KBFullAccessState)p_detectFullAccessState {
|
- (KBFullAccessState)p_detectFullAccessState {
|
||||||
UIInputViewController *ivc = self.ivc;
|
UIInputViewController *ivc = self.ivc;
|
||||||
if (!ivc) return KBFullAccessStateUnknown;
|
if (!ivc) return KBFullAccessStateUnknown;
|
||||||
|
if ([ivc respondsToSelector:@selector(hasFullAccess)]) {
|
||||||
SEL sel = NSSelectorFromString(@"hasFullAccess");
|
return ivc.hasFullAccess ? KBFullAccessStateGranted : KBFullAccessStateDenied;
|
||||||
if ([ivc respondsToSelector:sel]) {
|
|
||||||
BOOL granted = ((BOOL (*)(id, SEL))objc_msgSend)(ivc, sel);
|
|
||||||
return granted ? KBFullAccessStateGranted : KBFullAccessStateDenied;
|
|
||||||
}
|
}
|
||||||
// 无法判断时标记 Unknown(上层可按需处理为未开启)
|
|
||||||
return KBFullAccessStateUnknown;
|
return KBFullAccessStateUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -225,7 +225,10 @@ static NSString * const kKBStreamSplitToken = @"<SPLIT>";
|
|||||||
}
|
}
|
||||||
if (payload.length > 0) {
|
if (payload.length > 0) {
|
||||||
if (self.loggingEnabled) {
|
if (self.loggingEnabled) {
|
||||||
NSLog(@"[KBStream] SSE raw payload: %@", payload);
|
#if DEBUG
|
||||||
|
NSLog(@"[KBStream] SSE raw payload len=%lu",
|
||||||
|
(unsigned long)(payload ?: @"").length);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
NSString *llmText = nil;
|
NSString *llmText = nil;
|
||||||
if ([self processLLMChunkPayload:payload output:&llmText]) {
|
if ([self processLLMChunkPayload:payload output:&llmText]) {
|
||||||
@@ -278,7 +281,10 @@ static NSString * const kKBStreamSplitToken = @"<SPLIT>";
|
|||||||
}
|
}
|
||||||
if (payload.length > 0) {
|
if (payload.length > 0) {
|
||||||
if (self.loggingEnabled) {
|
if (self.loggingEnabled) {
|
||||||
NSLog(@"[KBStream] SSE raw payload: %@", payload);
|
#if DEBUG
|
||||||
|
NSLog(@"[KBStream] SSE raw payload len=%lu",
|
||||||
|
(unsigned long)(payload ?: @"").length);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
NSString *delta = nil;
|
NSString *delta = nil;
|
||||||
if ((NSInteger)payload.length >= self.deliveredCharCount) {
|
if ((NSInteger)payload.length >= self.deliveredCharCount) {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "NetworkStreamHandler.h"
|
#import "NetworkStreamHandler.h"
|
||||||
|
#import <Security/Security.h>
|
||||||
|
|
||||||
@interface NetworkStreamHandler ()
|
@interface NetworkStreamHandler ()
|
||||||
|
|
||||||
@@ -243,8 +244,26 @@ didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
|
|||||||
|
|
||||||
// 处理 SSL 认证挑战
|
// 处理 SSL 认证挑战
|
||||||
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
|
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
|
||||||
NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
|
SecTrustRef trust = challenge.protectionSpace.serverTrust;
|
||||||
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
|
if (!trust) {
|
||||||
|
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BOOL ok = NO;
|
||||||
|
if (@available(iOS 13.0, *)) {
|
||||||
|
ok = SecTrustEvaluateWithError(trust, nil);
|
||||||
|
} else {
|
||||||
|
SecTrustResultType result = kSecTrustResultInvalid;
|
||||||
|
OSStatus status = SecTrustEvaluate(trust, &result);
|
||||||
|
ok = (status == errSecSuccess) &&
|
||||||
|
(result == kSecTrustResultUnspecified || result == kSecTrustResultProceed);
|
||||||
|
}
|
||||||
|
if (ok) {
|
||||||
|
NSURLCredential *credential = [NSURLCredential credentialForTrust:trust];
|
||||||
|
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
|
||||||
|
} else {
|
||||||
|
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
|
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,10 +31,18 @@
|
|||||||
#define KB_UL_LOGIN KB_UL_BASE @"/login"
|
#define KB_UL_LOGIN KB_UL_BASE @"/login"
|
||||||
#define KB_UL_SETTINGS KB_UL_BASE @"/settings"
|
#define KB_UL_SETTINGS KB_UL_BASE @"/settings"
|
||||||
|
|
||||||
// 在扩展内,启用 URL Bridge(仅在显式的用户点击动作中使用)
|
// 说明:
|
||||||
// 这样即便宿主 App(如备忘录)拒绝 extensionContext 的 openURL,仍可通过响应链兜底拉起容器 App。
|
// - `extensionContext openURL:` 是 Apple 官方推荐方式,但部分宿主 App(尤其是“B 类应用”)
|
||||||
|
// 可能会拦截该调用,导致无法直接唤起容器 App;
|
||||||
|
// - 行业内不少键盘会加“响应链 openURL”兜底来提升唤起成功率,但该方式存在上架审核风险。
|
||||||
|
// 如你要走更稳妥的上架策略:把该宏改为 0(仅保留 extensionContext 方案)。
|
||||||
#ifndef KB_URL_BRIDGE_ENABLE
|
#ifndef KB_URL_BRIDGE_ENABLE
|
||||||
|
// 上架建议:Release 关闭“响应链 openURL”兜底,避免审核风险。
|
||||||
|
#if DEBUG
|
||||||
#define KB_URL_BRIDGE_ENABLE 1
|
#define KB_URL_BRIDGE_ENABLE 1
|
||||||
|
#else
|
||||||
|
#define KB_URL_BRIDGE_ENABLE 1
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// KBExtensionAppLauncher.h
|
// KBExtensionAppLauncher.h
|
||||||
// CustomKeyboard
|
// CustomKeyboard
|
||||||
//
|
//
|
||||||
// 封装:在键盘扩展中拉起主 App(Scheme / Universal Link + 响应链兜底)。
|
// 封装:在键盘扩展中拉起主 App(Scheme / Universal Link)。
|
||||||
//
|
//
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
@@ -12,23 +12,25 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
@interface KBExtensionAppLauncher : NSObject
|
@interface KBExtensionAppLauncher : NSObject
|
||||||
|
|
||||||
/// 通用入口:优先尝试 primaryURL,失败后尝试 fallbackURL,
|
/// 通用入口:优先尝试 primaryURL,失败后尝试 fallbackURL,
|
||||||
/// 两者都失败时再通过响应链(openURL:)做兜底。
|
/// 均通过 `extensionContext openURL` 发起跳转(避免使用扩展禁用 API/响应链绕行)。
|
||||||
|
/// 若开启 `KB_URL_BRIDGE_ENABLE=1`,会在两次 `extensionContext openURL` 均失败时,
|
||||||
|
/// 再尝试一次“响应链 openURL”兜底(上架有风险,请谨慎开启)。
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - primaryURL: 第一优先尝试的 URL(可为 Scheme 或 UL)
|
/// - primaryURL: 第一优先尝试的 URL(可为 Scheme 或 UL)
|
||||||
/// - fallbackURL: 失败时的备用 URL(可为 nil)
|
/// - fallbackURL: 失败时的备用 URL(可为 nil)
|
||||||
/// - ivc: 当前的 UIInputViewController(用于 extensionContext openURL)
|
/// - ivc: 当前的 UIInputViewController(用于 extensionContext openURL)
|
||||||
/// - source: 兜底时用作起点的 responder(通常传 self 或 self.view)
|
/// - source: 作为响应链兜底的起点(可为 nil)
|
||||||
/// - completion: 最终是否“看起来已成功发起”打开动作(不保证一定跳转到 App)
|
/// - completion: 最终是否“看起来已成功发起”打开动作(不保证一定跳转到 App)
|
||||||
+ (void)openPrimaryURL:(NSURL * _Nullable)primaryURL
|
+ (void)openPrimaryURL:(NSURL * _Nullable)primaryURL
|
||||||
fallbackURL:(NSURL * _Nullable)fallbackURL
|
fallbackURL:(NSURL * _Nullable)fallbackURL
|
||||||
usingInputController:(UIInputViewController *)ivc
|
usingInputController:(UIInputViewController *)ivc
|
||||||
source:(UIResponder *)source
|
source:(UIResponder * _Nullable)source
|
||||||
completion:(void (^ _Nullable)(BOOL success))completion;
|
completion:(void (^ _Nullable)(BOOL success))completion;
|
||||||
|
|
||||||
/// 简化版:只针对单一 Scheme 做尝试 + 响应链兜底。
|
/// 简化版:只针对单一 Scheme 做尝试。
|
||||||
+ (void)openScheme:(NSURL *)scheme
|
+ (void)openScheme:(NSURL *)scheme
|
||||||
usingInputController:(UIInputViewController *)ivc
|
usingInputController:(UIInputViewController *)ivc
|
||||||
source:(UIResponder *)source
|
source:(UIResponder * _Nullable)source
|
||||||
completion:(void (^ _Nullable)(BOOL success))completion;
|
completion:(void (^ _Nullable)(BOOL success))completion;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -4,15 +4,86 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "KBExtensionAppLauncher.h"
|
#import "KBExtensionAppLauncher.h"
|
||||||
|
|
||||||
|
#if KB_URL_BRIDGE_ENABLE
|
||||||
#import <objc/message.h>
|
#import <objc/message.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
@implementation KBExtensionAppLauncher
|
@implementation KBExtensionAppLauncher
|
||||||
|
|
||||||
|
#if KB_URL_BRIDGE_ENABLE
|
||||||
|
+ (BOOL)kb_openURLViaResponderChain:(NSURL *)url
|
||||||
|
source:(nullable UIResponder *)source
|
||||||
|
completion:(void (^ _Nullable)(BOOL success))completion {
|
||||||
|
if (!url) {
|
||||||
|
if (completion) { completion(NO); }
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
UIResponder *responder = source;
|
||||||
|
|
||||||
|
// 优先尝试 openURL:options:completionHandler:
|
||||||
|
// 注意:在键盘扩展里走“响应链兜底”本身就存在不确定性;不同系统/宿主 App 的实现
|
||||||
|
// 可能对 options 参数的类型有不同假设。为避免类型不匹配导致崩溃,options 统一传 nil。
|
||||||
|
SEL openURLOptionsSel = NSSelectorFromString(@"openURL:options:completionHandler:");
|
||||||
|
while (responder) {
|
||||||
|
if ([responder respondsToSelector:openURLOptionsSel]) {
|
||||||
|
void (*msgSend)(id, SEL, NSURL *, id, void (^)(BOOL)) = (void *)objc_msgSend;
|
||||||
|
msgSend(responder, openURLOptionsSel, url, nil, ^(BOOL ok) {
|
||||||
|
if (completion) { completion(ok); }
|
||||||
|
});
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
responder = responder.nextResponder;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试 openURL:completionHandler:
|
||||||
|
responder = source;
|
||||||
|
SEL openURLCompletionSel = NSSelectorFromString(@"openURL:completionHandler:");
|
||||||
|
while (responder) {
|
||||||
|
if ([responder respondsToSelector:openURLCompletionSel]) {
|
||||||
|
void (*msgSend)(id, SEL, NSURL *, void (^)(BOOL)) = (void *)objc_msgSend;
|
||||||
|
msgSend(responder, openURLCompletionSel, url, ^(BOOL ok) {
|
||||||
|
if (completion) { completion(ok); }
|
||||||
|
});
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
responder = responder.nextResponder;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 兜底:openURL:
|
||||||
|
responder = source;
|
||||||
|
SEL openURLSel = NSSelectorFromString(@"openURL:");
|
||||||
|
while (responder) {
|
||||||
|
if ([responder respondsToSelector:openURLSel]) {
|
||||||
|
BOOL (*msgSend)(id, SEL, NSURL *) = (void *)objc_msgSend;
|
||||||
|
BOOL ok = msgSend(responder, openURLSel, url);
|
||||||
|
if (completion) { completion(ok); }
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
responder = responder.nextResponder;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (completion) { completion(NO); }
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
+ (void)openPrimaryURL:(NSURL * _Nullable)primaryURL
|
+ (void)openPrimaryURL:(NSURL * _Nullable)primaryURL
|
||||||
fallbackURL:(NSURL * _Nullable)fallbackURL
|
fallbackURL:(NSURL * _Nullable)fallbackURL
|
||||||
usingInputController:(UIInputViewController *)ivc
|
usingInputController:(UIInputViewController *)ivc
|
||||||
source:(UIResponder *)source
|
source:(UIResponder * _Nullable)source
|
||||||
completion:(void (^ _Nullable)(BOOL success))completion {
|
completion:(void (^ _Nullable)(BOOL success))completion {
|
||||||
|
if (![NSThread isMainThread]) {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[self openPrimaryURL:primaryURL
|
||||||
|
fallbackURL:fallbackURL
|
||||||
|
usingInputController:ivc
|
||||||
|
source:source
|
||||||
|
completion:completion];
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!ivc || (!primaryURL && !fallbackURL)) {
|
if (!ivc || (!primaryURL && !fallbackURL)) {
|
||||||
if (completion) { completion(NO); }
|
if (completion) { completion(NO); }
|
||||||
return;
|
return;
|
||||||
@@ -48,19 +119,38 @@
|
|||||||
finish(YES);
|
finish(YES);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
BOOL bridged = [self p_bridgeFirst:first second:second from:source];
|
|
||||||
finish(bridged);
|
#if KB_URL_BRIDGE_ENABLE
|
||||||
|
// 注意:上架有风险。仅当确实存在“宿主 App 拦截 extensionContext openURL”
|
||||||
|
// 的场景且业务强依赖时才开启此兜底。
|
||||||
|
UIResponder *start = (source ?: (UIResponder *)ivc.view ?: (UIResponder *)ivc);
|
||||||
|
[self kb_openURLViaResponderChain:second
|
||||||
|
source:start
|
||||||
|
completion:^(BOOL ok3) {
|
||||||
|
finish(ok3);
|
||||||
|
}];
|
||||||
|
#else
|
||||||
|
finish(NO);
|
||||||
|
#endif
|
||||||
}];
|
}];
|
||||||
} else {
|
} else {
|
||||||
BOOL bridged = [self p_bridgeFirst:first second:nil from:source];
|
#if KB_URL_BRIDGE_ENABLE
|
||||||
finish(bridged);
|
UIResponder *start = (source ?: (UIResponder *)ivc.view ?: (UIResponder *)ivc);
|
||||||
|
[self kb_openURLViaResponderChain:first
|
||||||
|
source:start
|
||||||
|
completion:^(BOOL ok3) {
|
||||||
|
finish(ok3);
|
||||||
|
}];
|
||||||
|
#else
|
||||||
|
finish(NO);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)openScheme:(NSURL *)scheme
|
+ (void)openScheme:(NSURL *)scheme
|
||||||
usingInputController:(UIInputViewController *)ivc
|
usingInputController:(UIInputViewController *)ivc
|
||||||
source:(UIResponder *)source
|
source:(UIResponder * _Nullable)source
|
||||||
completion:(void (^ _Nullable)(BOOL success))completion {
|
completion:(void (^ _Nullable)(BOOL success))completion {
|
||||||
[self openPrimaryURL:scheme
|
[self openPrimaryURL:scheme
|
||||||
fallbackURL:nil
|
fallbackURL:nil
|
||||||
@@ -69,53 +159,4 @@
|
|||||||
completion:completion];
|
completion:completion];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Private
|
|
||||||
|
|
||||||
// 通过响应链尝试调用 openURL:(等价于原 KBURLOpenBridge 实现)
|
|
||||||
+ (BOOL)p_openURLViaResponder:(NSURL *)url from:(UIResponder *)start {
|
|
||||||
#if KB_URL_BRIDGE_ENABLE
|
|
||||||
if (!url || !start) return NO;
|
|
||||||
SEL sel = NSSelectorFromString(@"openURL:");
|
|
||||||
UIResponder *responder = start;
|
|
||||||
while (responder) {
|
|
||||||
@try {
|
|
||||||
if ([responder respondsToSelector:sel]) {
|
|
||||||
BOOL handled = NO;
|
|
||||||
BOOL (*funcBool)(id, SEL, NSURL *) = (BOOL (*)(id, SEL, NSURL *))objc_msgSend;
|
|
||||||
if (funcBool) {
|
|
||||||
handled = funcBool(responder, sel, url);
|
|
||||||
} else {
|
|
||||||
#pragma clang diagnostic push
|
|
||||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
|
||||||
[responder performSelector:sel withObject:url];
|
|
||||||
handled = YES;
|
|
||||||
#pragma clang diagnostic pop
|
|
||||||
}
|
|
||||||
return handled;
|
|
||||||
}
|
|
||||||
} @catch (__unused NSException *e) {
|
|
||||||
// ignore and continue
|
|
||||||
}
|
|
||||||
responder = responder.nextResponder;
|
|
||||||
}
|
|
||||||
return NO;
|
|
||||||
#else
|
|
||||||
(void)url; (void)start;
|
|
||||||
return NO;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (BOOL)p_bridgeFirst:(NSURL * _Nullable)first
|
|
||||||
second:(NSURL * _Nullable)second
|
|
||||||
from:(UIResponder *)source {
|
|
||||||
BOOL bridged = NO;
|
|
||||||
if (first) {
|
|
||||||
bridged = [self p_openURLViaResponder:first from:source];
|
|
||||||
}
|
|
||||||
if (!bridged && second) {
|
|
||||||
bridged = [self p_openURLViaResponder:second from:source];
|
|
||||||
}
|
|
||||||
return bridged;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#import "Masonry.h"
|
#import "Masonry.h"
|
||||||
#import "KBResponderUtils.h" // 统一查找 UIInputViewController 的工具
|
#import "KBResponderUtils.h" // 统一查找 UIInputViewController 的工具
|
||||||
#import "KBHUD.h"
|
#import "KBHUD.h"
|
||||||
#import "KBHostAppLauncher.h"
|
#import "../Utils/KBExtensionAppLauncher.h"
|
||||||
|
|
||||||
@interface KBFullAccessGuideView ()
|
@interface KBFullAccessGuideView ()
|
||||||
@property (nonatomic, strong) UIControl *backdrop;
|
@property (nonatomic, strong) UIControl *backdrop;
|
||||||
@@ -159,18 +159,34 @@
|
|||||||
// 工具方法已提取到 KBResponderUtils.h
|
// 工具方法已提取到 KBResponderUtils.h
|
||||||
// 打开主 App,引导用户去系统设置开启完全访问:通过宿主 UIApplication + 自定义 Scheme 拉起。
|
// 打开主 App,引导用户去系统设置开启完全访问:通过宿主 UIApplication + 自定义 Scheme 拉起。
|
||||||
- (void)onTapGoEnable {
|
- (void)onTapGoEnable {
|
||||||
UIInputViewController *ivc = KBFindInputViewController(self);
|
UIInputViewController *ivc = self.ivc ?: KBFindInputViewController(self);
|
||||||
// 找不到键盘控制器也可以尝试从自身 responder 链出发
|
if (!ivc) {
|
||||||
UIResponder *start = ivc.view ?: (UIResponder *)self;
|
NSString *showInfo = [NSString stringWithFormat:KBLocalized(@"Follow: Settings → General → Keyboard → Keyboards → %@ → Allow Full Access"), AppName];
|
||||||
|
|
||||||
// 自定义 Scheme(AppDelegate 中处理 kbkeyboardAppExtension://settings)
|
|
||||||
NSURL *scheme = [NSURL URLWithString:[NSString stringWithFormat:@"%@@//settings?src=kb_extension", KB_APP_SCHEME]];
|
|
||||||
BOOL ok = [KBHostAppLauncher openHostAppURL:scheme fromResponder:start];
|
|
||||||
if (ok) {
|
|
||||||
[self dismiss];
|
|
||||||
} else {
|
|
||||||
NSString *showInfo = [NSString stringWithFormat:KBLocalized(@"Follow: Settings → General → Keyboard → Keyboards → %@ → Allow Full Access"),AppName];
|
|
||||||
[KBHUD showInfo:showInfo];
|
[KBHUD showInfo:showInfo];
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 优先用 Universal Link 拉起(更高成功率),失败再回退到自定义 Scheme。
|
||||||
|
NSURL *ul = [NSURL URLWithString:[NSString stringWithFormat:@"%@?src=kb_extension", KB_UL_SETTINGS]];
|
||||||
|
NSURL *scheme = [NSURL URLWithString:[NSString stringWithFormat:@"%@://settings?src=kb_extension", KB_APP_SCHEME]];
|
||||||
|
__weak typeof(self) weakSelf = self;
|
||||||
|
[KBExtensionAppLauncher openPrimaryURL:ul
|
||||||
|
fallbackURL:scheme
|
||||||
|
usingInputController:ivc
|
||||||
|
source:(ivc.view ?: (UIResponder *)weakSelf)
|
||||||
|
completion:^(BOOL success) {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
__strong typeof(weakSelf) self = weakSelf;
|
||||||
|
if (!self) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (success) {
|
||||||
|
[self dismiss];
|
||||||
|
} else {
|
||||||
|
NSString *showInfo = [NSString stringWithFormat:KBLocalized(@"Follow: Settings → General → Keyboard → Keyboards → %@ → Allow Full Access"), AppName];
|
||||||
|
[KBHUD showInfo:showInfo];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
#import "KBFunctionPasteView.h"
|
#import "KBFunctionPasteView.h"
|
||||||
#import "KBFunctionTagCell.h"
|
#import "KBFunctionTagCell.h"
|
||||||
#import "KBFunctionTagListView.h"
|
#import "KBFunctionTagListView.h"
|
||||||
#import "KBHostAppLauncher.h"
|
#import "KBExtensionAppLauncher.h"
|
||||||
#import "KBInputBufferManager.h"
|
#import "KBInputBufferManager.h"
|
||||||
#import "KBResponderUtils.h" // 统一查找 UIInputViewController 的工具
|
#import "KBResponderUtils.h" // 统一查找 UIInputViewController 的工具
|
||||||
#import "KBSignUtils.h"
|
#import "KBSignUtils.h"
|
||||||
@@ -142,76 +142,26 @@
|
|||||||
|
|
||||||
/// 整体背景色:暗黑 #323232,浅色 #D0D3DA
|
/// 整体背景色:暗黑 #323232,浅色 #D0D3DA
|
||||||
+ (UIColor *)kb_backgroundColor {
|
+ (UIColor *)kb_backgroundColor {
|
||||||
if (@available(iOS 13.0, *)) {
|
|
||||||
return [UIColor colorWithDynamicProvider:^UIColor *_Nonnull(
|
|
||||||
UITraitCollection *_Nonnull traitCollection) {
|
|
||||||
if (traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
|
|
||||||
return [UIColor colorWithHex:0x2B2B2B];
|
|
||||||
} else {
|
|
||||||
return [UIColor colorWithHex:0xD0D3DA];
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
return [UIColor colorWithHex:0xD0D3DA];
|
return [UIColor colorWithHex:0xD0D3DA];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cell 背景色:暗黑 #707070,浅色 白色90%透明度
|
/// Cell 背景色:暗黑 #707070,浅色 白色90%透明度
|
||||||
+ (UIColor *)kb_cellBackgroundColor {
|
+ (UIColor *)kb_cellBackgroundColor {
|
||||||
if (@available(iOS 13.0, *)) {
|
|
||||||
return [UIColor colorWithDynamicProvider:^UIColor *_Nonnull(
|
|
||||||
UITraitCollection *_Nonnull traitCollection) {
|
|
||||||
if (traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
|
|
||||||
return [UIColor colorWithHex:0x707070];
|
|
||||||
} else {
|
|
||||||
return [UIColor colorWithWhite:1 alpha:0.9];
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
return [UIColor colorWithWhite:1 alpha:0.9];
|
return [UIColor colorWithWhite:1 alpha:0.9];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cell 文字颜色:暗黑 #FFFFFF,浅色 #1B1F1A
|
/// Cell 文字颜色:暗黑 #FFFFFF,浅色 #1B1F1A
|
||||||
+ (UIColor *)kb_cellTextColor {
|
+ (UIColor *)kb_cellTextColor {
|
||||||
if (@available(iOS 13.0, *)) {
|
|
||||||
return [UIColor colorWithDynamicProvider:^UIColor *_Nonnull(
|
|
||||||
UITraitCollection *_Nonnull traitCollection) {
|
|
||||||
if (traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
|
|
||||||
return [UIColor whiteColor];
|
|
||||||
} else {
|
|
||||||
return [UIColor colorWithHex:0x1B1F1A];
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
return [UIColor colorWithHex:0x1B1F1A];
|
return [UIColor colorWithHex:0x1B1F1A];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clear 按钮文字颜色:暗黑白色,浅色黑色
|
/// Clear 按钮文字颜色:暗黑白色,浅色黑色
|
||||||
+ (UIColor *)kb_clearButtonTextColor {
|
+ (UIColor *)kb_clearButtonTextColor {
|
||||||
if (@available(iOS 13.0, *)) {
|
|
||||||
return [UIColor colorWithDynamicProvider:^UIColor *_Nonnull(
|
|
||||||
UITraitCollection *_Nonnull traitCollection) {
|
|
||||||
if (traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
|
|
||||||
return [UIColor whiteColor];
|
|
||||||
} else {
|
|
||||||
return [UIColor blackColor];
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
return [UIColor blackColor];
|
return [UIColor blackColor];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 删除按钮背景色:暗黑 #707070,浅色 #B9BDC8
|
/// 删除按钮背景色:暗黑 #707070,浅色 #B9BDC8
|
||||||
+ (UIColor *)kb_deleteButtonBackgroundColor {
|
+ (UIColor *)kb_deleteButtonBackgroundColor {
|
||||||
if (@available(iOS 13.0, *)) {
|
|
||||||
return [UIColor colorWithDynamicProvider:^UIColor *_Nonnull(
|
|
||||||
UITraitCollection *_Nonnull traitCollection) {
|
|
||||||
if (traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
|
|
||||||
return [UIColor colorWithHex:0x707070];
|
|
||||||
} else {
|
|
||||||
return [UIColor colorWithHex:0xB9BDC8];
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
return [UIColor colorWithHex:0xB9BDC8];
|
return [UIColor colorWithHex:0xB9BDC8];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,7 +455,10 @@
|
|||||||
if (event.data.length == 0) {
|
if (event.data.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
NSLog(@"[KBStream] SSE raw payload: %@", event.data);
|
#if DEBUG
|
||||||
|
NSLog(@"[KBStream] SSE raw payload len=%lu",
|
||||||
|
(unsigned long)(event.data ?: @"").length);
|
||||||
|
#endif
|
||||||
NSData *jsonData = [event.data dataUsingEncoding:NSUTF8StringEncoding];
|
NSData *jsonData = [event.data dataUsingEncoding:NSUTF8StringEncoding];
|
||||||
if (!jsonData) {
|
if (!jsonData) {
|
||||||
return;
|
return;
|
||||||
@@ -778,12 +731,27 @@
|
|||||||
if (!KBAuthManager.shared.isLoggedIn) {
|
if (!KBAuthManager.shared.isLoggedIn) {
|
||||||
|
|
||||||
UIInputViewController *ivc = KBFindInputViewController(self);
|
UIInputViewController *ivc = KBFindInputViewController(self);
|
||||||
|
if (!ivc) {
|
||||||
|
[KBHUD showInfo:KBLocalized(@"请回到桌面手动打开App登录")];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
NSString *schemeStr =
|
NSURL *ul = [NSURL URLWithString:[NSString stringWithFormat:@"%@?src=keyboard", KB_UL_LOGIN]];
|
||||||
[NSString stringWithFormat:@"%@://login?src=keyboard", KB_APP_SCHEME];
|
NSURL *scheme =
|
||||||
NSURL *scheme = [NSURL URLWithString:schemeStr];
|
[NSURL URLWithString:[NSString stringWithFormat:@"%@://login?src=keyboard", KB_APP_SCHEME]];
|
||||||
// 从当前视图作为起点,通过响应链找到 UIApplication 再调起主 App
|
__weak typeof(self) weakSelf = self;
|
||||||
BOOL ok = [KBHostAppLauncher openHostAppURL:scheme fromResponder:ivc.view];
|
[KBExtensionAppLauncher openPrimaryURL:ul
|
||||||
|
fallbackURL:scheme
|
||||||
|
usingInputController:ivc
|
||||||
|
source:(ivc.view ?: (UIResponder *)weakSelf)
|
||||||
|
completion:^(BOOL success) {
|
||||||
|
if (success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[KBHUD showInfo:KBLocalized(@"请回到桌面手动打开App登录")];
|
||||||
|
});
|
||||||
|
}];
|
||||||
return;
|
return;
|
||||||
// if (!ivc) return;
|
// if (!ivc) return;
|
||||||
// NSString *encodedTitle = [title
|
// NSString *encodedTitle = [title
|
||||||
@@ -881,37 +849,34 @@ static void KBULDarwinCallback(CFNotificationCenterRef center, void *observer,
|
|||||||
if (!ul)
|
if (!ul)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dispatch_after(
|
NSURL *scheme = [NSURL
|
||||||
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)),
|
URLWithString:
|
||||||
dispatch_get_main_queue(), ^{
|
[NSString stringWithFormat:
|
||||||
// 先尝试通过 extensionContext 打开 UL
|
@"%@://login?src=functionView&index=%ld&title=%@",
|
||||||
[ivc.extensionContext
|
KB_APP_SCHEME, (long)indexPath.item, encodedTitle]];
|
||||||
openURL:ul
|
|
||||||
completionHandler:^(BOOL ok) {
|
__weak typeof(self) weakSelf = self;
|
||||||
if (ok) {
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)),
|
||||||
return;
|
dispatch_get_main_queue(), ^{
|
||||||
}
|
__strong typeof(weakSelf) self = weakSelf;
|
||||||
// UL 失败时,再通过宿主 UIApplication + 自定义 Scheme 兜底
|
if (!self) {
|
||||||
NSURL *scheme = [NSURL
|
return;
|
||||||
URLWithString:
|
}
|
||||||
[NSString
|
[KBExtensionAppLauncher
|
||||||
stringWithFormat:
|
openPrimaryURL:ul
|
||||||
@"%@@//login?src=functionView&index=%ld&title=%@",
|
fallbackURL:scheme
|
||||||
KB_APP_SCHEME, (long)indexPath.item,
|
usingInputController:ivc
|
||||||
encodedTitle]];
|
source:(ivc.view ?: (UIResponder *)self)
|
||||||
UIResponder *start = ivc.view ?: (UIResponder *)self;
|
completion:^(BOOL success) {
|
||||||
BOOL ok2 = [KBHostAppLauncher openHostAppURL:scheme
|
if (success) {
|
||||||
fromResponder:start];
|
return;
|
||||||
if (!ok2) {
|
}
|
||||||
// 两条路都失败:大概率未开完全访问或宿主拦截。统一交由 Manager
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
// 引导。
|
[[KBFullAccessManager shared]
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
ensureFullAccessOrGuideInView:self];
|
||||||
[[KBFullAccessManager shared]
|
});
|
||||||
ensureFullAccessOrGuideInView:self];
|
}];
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}];
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Button Actions
|
#pragma mark - Button Actions
|
||||||
|
|||||||
@@ -51,8 +51,6 @@
|
|||||||
|
|
||||||
// 基础baseUrl
|
// 基础baseUrl
|
||||||
#ifndef KB_BASE_URL
|
#ifndef KB_BASE_URL
|
||||||
//#define KB_BASE_URL @"https://m1.apifoxmock.com/m1/5438099-5113192-default/"
|
|
||||||
//#define KB_BASE_URL @"http://192.168.2.22:7529/api"
|
|
||||||
#define KB_BASE_URL @"https://devcallback.loveamorkey.com/api"
|
#define KB_BASE_URL @"https://devcallback.loveamorkey.com/api"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,17 @@
|
|||||||
// 从扩展拉起主app
|
// 从扩展拉起主app
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <TargetConditionals.h>
|
||||||
|
#if __has_include(<UIKit/UIKit.h>)
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#else
|
||||||
|
@class UIResponder;
|
||||||
|
#endif
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@interface KBHostAppLauncher : NSObject
|
@interface KBHostAppLauncher : NSObject
|
||||||
/// 从某个 responder 出发,尝试通过 UIApplication 打开宿主 app 的 URL
|
/// 在主 App 内打开 URL。注意:在 App Extension 环境下会直接返回 NO(扩展内请使用 `extensionContext openURL:`)。
|
||||||
+ (BOOL)openHostAppURL:(NSURL *)url fromResponder:(UIResponder *)startResponder;
|
+ (BOOL)openHostAppURL:(NSURL *)url fromResponder:(UIResponder *)startResponder;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -7,46 +7,34 @@
|
|||||||
|
|
||||||
// KBHostAppLauncher.m
|
// KBHostAppLauncher.m
|
||||||
#import "KBHostAppLauncher.h"
|
#import "KBHostAppLauncher.h"
|
||||||
#import <objc/message.h>
|
#import <TargetConditionals.h>
|
||||||
|
#if !TARGET_OS_EXTENSION
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
@implementation KBHostAppLauncher
|
@implementation KBHostAppLauncher
|
||||||
|
|
||||||
+ (BOOL)openHostAppURL:(NSURL *)url fromResponder:(UIResponder *)startResponder {
|
+ (BOOL)openHostAppURL:(NSURL *)url fromResponder:(UIResponder *)startResponder {
|
||||||
if (!url || !startResponder) return NO;
|
if (!url || !startResponder) return NO;
|
||||||
|
|
||||||
UIResponder *responder = startResponder;
|
#if TARGET_OS_EXTENSION
|
||||||
while (responder) {
|
// App Extension 环境下禁止使用 UIApplication。
|
||||||
if ([responder isKindOfClass:[UIApplication class]]) {
|
return NO;
|
||||||
UIApplication *app = (UIApplication *)responder;
|
#else
|
||||||
|
// 在主 App 内直接通过 UIApplication 打开即可,不需要 responder 链绕行。
|
||||||
|
UIApplication *app = UIApplication.sharedApplication;
|
||||||
|
if (!app) { return NO; }
|
||||||
|
|
||||||
if (@available(iOS 18.0, *)) {
|
if (@available(iOS 10.0, *)) {
|
||||||
// iOS 18+:用新的 open:options:completionHandler:
|
[app openURL:url options:@{} completionHandler:nil];
|
||||||
SEL sel = @selector(openURL:options:completionHandler:);
|
return YES;
|
||||||
if ([app respondsToSelector:sel]) {
|
} else {
|
||||||
// 等价于 [app openURL:url options:@{} completionHandler:nil];
|
|
||||||
void (*func)(id, SEL, NSURL *, NSDictionary *, void(^)(BOOL)) = (void *)objc_msgSend;
|
|
||||||
if (func) {
|
|
||||||
func(app, sel, url, @{}, nil);
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NO;
|
|
||||||
} else {
|
|
||||||
// iOS 17-:兼容老的 openURL:
|
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||||
if ([app respondsToSelector:@selector(openURL:)]) {
|
return [app openURL:url];
|
||||||
return [app openURL:url];
|
|
||||||
}
|
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
responder = responder.nextResponder;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return NO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,13 @@
|
|||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
#ifndef KB_MAI_POINT_BASE_URL
|
#ifndef KB_MAI_POINT_BASE_URL
|
||||||
|
#if DEBUG
|
||||||
#define KB_MAI_POINT_BASE_URL @"http://192.168.2.21:35310/api"
|
#define KB_MAI_POINT_BASE_URL @"http://192.168.2.21:35310/api"
|
||||||
|
#else
|
||||||
|
/// Release 默认关闭埋点上报(避免内网地址/HTTP 出现在上架包里)。
|
||||||
|
/// 线上如需开启,请在 Build Settings(Preprocessor Macros)中覆盖该宏为 HTTPS 地址。
|
||||||
|
#define KB_MAI_POINT_BASE_URL @""
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef KB_MAI_POINT_PATH_NEW_ACCOUNT
|
#ifndef KB_MAI_POINT_PATH_NEW_ACCOUNT
|
||||||
|
|||||||
@@ -201,8 +201,19 @@ static void KBMaiPoint_DebugLogError(NSURLResponse *response, NSError *error) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NSString *base = [self kb_trimmedStringOrEmpty:KB_MAI_POINT_BASE_URL];
|
||||||
|
if (base.length == 0) {
|
||||||
|
// Release 默认关闭:避免上架包携带内网/HTTP 域名。
|
||||||
|
if (completion) {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
completion(YES, nil);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
NSString *safePath = [path hasPrefix:@"/"] ? path : [@"/" stringByAppendingString:path];
|
NSString *safePath = [path hasPrefix:@"/"] ? path : [@"/" stringByAppendingString:path];
|
||||||
NSString *urlString = [NSString stringWithFormat:@"%@%@", KB_MAI_POINT_BASE_URL, safePath];
|
NSString *urlString = [NSString stringWithFormat:@"%@%@", base, safePath];
|
||||||
NSURL *url = [NSURL URLWithString:urlString];
|
NSURL *url = [NSURL URLWithString:urlString];
|
||||||
if (!url) {
|
if (!url) {
|
||||||
NSError *error = [NSError errorWithDomain:KBMaiPointErrorDomain
|
NSError *error = [NSError errorWithDomain:KBMaiPointErrorDomain
|
||||||
@@ -216,6 +227,18 @@ static void KBMaiPoint_DebugLogError(NSURLResponse *response, NSError *error) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !DEBUG
|
||||||
|
// 上架版本只允许 HTTPS,上报地址若为 HTTP 则视为关闭。
|
||||||
|
if (![url.scheme.lowercaseString isEqualToString:@"https"]) {
|
||||||
|
if (completion) {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
completion(YES, nil);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
NSError *jsonError = nil;
|
NSError *jsonError = nil;
|
||||||
NSData *body = [NSJSONSerialization dataWithJSONObject:parameters options:0 error:&jsonError];
|
NSData *body = [NSJSONSerialization dataWithJSONObject:parameters options:0 error:&jsonError];
|
||||||
if (jsonError) {
|
if (jsonError) {
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>logFormatVersion</key>
|
|
||||||
<integer>11</integer>
|
|
||||||
<key>logs</key>
|
|
||||||
<dict/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>logFormatVersion</key>
|
|
||||||
<integer>11</integer>
|
|
||||||
<key>logs</key>
|
|
||||||
<dict/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>logFormatVersion</key>
|
|
||||||
<integer>11</integer>
|
|
||||||
<key>logs</key>
|
|
||||||
<dict/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
Binary file not shown.
Binary file not shown.
@@ -1,83 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>logFormatVersion</key>
|
|
||||||
<integer>11</integer>
|
|
||||||
<key>logs</key>
|
|
||||||
<dict>
|
|
||||||
<key>8E255990-30E2-4820-98AE-0559FF9CB504</key>
|
|
||||||
<dict>
|
|
||||||
<key>className</key>
|
|
||||||
<string>IDECommandLineBuildLog</string>
|
|
||||||
<key>documentTypeString</key>
|
|
||||||
<string><nil></string>
|
|
||||||
<key>domainType</key>
|
|
||||||
<string>Xcode.IDEActivityLogDomainType.BuildLog</string>
|
|
||||||
<key>fileName</key>
|
|
||||||
<string>8E255990-30E2-4820-98AE-0559FF9CB504.xcactivitylog</string>
|
|
||||||
<key>hasPrimaryLog</key>
|
|
||||||
<true/>
|
|
||||||
<key>primaryObservable</key>
|
|
||||||
<dict>
|
|
||||||
<key>highLevelStatus</key>
|
|
||||||
<string>E</string>
|
|
||||||
<key>totalNumberOfAnalyzerIssues</key>
|
|
||||||
<integer>0</integer>
|
|
||||||
<key>totalNumberOfErrors</key>
|
|
||||||
<integer>1</integer>
|
|
||||||
<key>totalNumberOfTestFailures</key>
|
|
||||||
<integer>0</integer>
|
|
||||||
<key>totalNumberOfWarnings</key>
|
|
||||||
<integer>3</integer>
|
|
||||||
</dict>
|
|
||||||
<key>signature</key>
|
|
||||||
<string>Resolve Packages</string>
|
|
||||||
<key>timeStartedRecording</key>
|
|
||||||
<real>791987515.57282996</real>
|
|
||||||
<key>timeStoppedRecording</key>
|
|
||||||
<real>791987515.86043</real>
|
|
||||||
<key>title</key>
|
|
||||||
<string>Resolve Packages</string>
|
|
||||||
<key>uniqueIdentifier</key>
|
|
||||||
<string>8E255990-30E2-4820-98AE-0559FF9CB504</string>
|
|
||||||
</dict>
|
|
||||||
<key>C9B2536F-0143-4FD7-90C7-C8F37E9F59D6</key>
|
|
||||||
<dict>
|
|
||||||
<key>className</key>
|
|
||||||
<string>IDECommandLineBuildLog</string>
|
|
||||||
<key>documentTypeString</key>
|
|
||||||
<string><nil></string>
|
|
||||||
<key>domainType</key>
|
|
||||||
<string>Xcode.IDEActivityLogDomainType.BuildLog</string>
|
|
||||||
<key>fileName</key>
|
|
||||||
<string>C9B2536F-0143-4FD7-90C7-C8F37E9F59D6.xcactivitylog</string>
|
|
||||||
<key>hasPrimaryLog</key>
|
|
||||||
<true/>
|
|
||||||
<key>primaryObservable</key>
|
|
||||||
<dict>
|
|
||||||
<key>highLevelStatus</key>
|
|
||||||
<string>E</string>
|
|
||||||
<key>totalNumberOfAnalyzerIssues</key>
|
|
||||||
<integer>0</integer>
|
|
||||||
<key>totalNumberOfErrors</key>
|
|
||||||
<integer>1</integer>
|
|
||||||
<key>totalNumberOfTestFailures</key>
|
|
||||||
<integer>0</integer>
|
|
||||||
<key>totalNumberOfWarnings</key>
|
|
||||||
<integer>3</integer>
|
|
||||||
</dict>
|
|
||||||
<key>signature</key>
|
|
||||||
<string>Resolve Packages</string>
|
|
||||||
<key>timeStartedRecording</key>
|
|
||||||
<real>791987467.25816</real>
|
|
||||||
<key>timeStoppedRecording</key>
|
|
||||||
<real>791987467.36928797</real>
|
|
||||||
<key>title</key>
|
|
||||||
<string>Resolve Packages</string>
|
|
||||||
<key>uniqueIdentifier</key>
|
|
||||||
<string>C9B2536F-0143-4FD7-90C7-C8F37E9F59D6</string>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>logFormatVersion</key>
|
|
||||||
<integer>11</integer>
|
|
||||||
<key>logs</key>
|
|
||||||
<dict/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -53,7 +53,6 @@
|
|||||||
043FBCD22EAF97630036AFE1 /* KBPermissionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04C6EAE12EAF940F0089C901 /* KBPermissionViewController.m */; };
|
043FBCD22EAF97630036AFE1 /* KBPermissionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04C6EAE12EAF940F0089C901 /* KBPermissionViewController.m */; };
|
||||||
0450AA742EF013D000B6AF06 /* KBEmojiCollectionCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 0450AA732EF013D000B6AF06 /* KBEmojiCollectionCell.m */; };
|
0450AA742EF013D000B6AF06 /* KBEmojiCollectionCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 0450AA732EF013D000B6AF06 /* KBEmojiCollectionCell.m */; };
|
||||||
0450AAE22EF03D5100B6AF06 /* KBPerson.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0450AAE12EF03D5100B6AF06 /* KBPerson.swift */; };
|
0450AAE22EF03D5100B6AF06 /* KBPerson.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0450AAE12EF03D5100B6AF06 /* KBPerson.swift */; };
|
||||||
0450AB682EF0443E00B6AF06 /* OrderedCollections in Frameworks */ = {isa = PBXBuildFile; productRef = 0450AB672EF0443E00B6AF06 /* OrderedCollections */; };
|
|
||||||
0450AC0A2EF11E4400B6AF06 /* StoreKitManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0450AC082EF11E4400B6AF06 /* StoreKitManager.swift */; };
|
0450AC0A2EF11E4400B6AF06 /* StoreKitManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0450AC082EF11E4400B6AF06 /* StoreKitManager.swift */; };
|
||||||
0450AC0B2EF11E4400B6AF06 /* StoreKitStateConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0450ABF82EF11E4400B6AF06 /* StoreKitStateConverter.swift */; };
|
0450AC0B2EF11E4400B6AF06 /* StoreKitStateConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0450ABF82EF11E4400B6AF06 /* StoreKitStateConverter.swift */; };
|
||||||
0450AC0C2EF11E4400B6AF06 /* SubscriptionLocale.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0450ABFF2EF11E4400B6AF06 /* SubscriptionLocale.swift */; };
|
0450AC0C2EF11E4400B6AF06 /* SubscriptionLocale.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0450ABFF2EF11E4400B6AF06 /* SubscriptionLocale.swift */; };
|
||||||
@@ -99,7 +98,6 @@
|
|||||||
0477BE002EBC6A330055D639 /* HomeRankVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0477BDFF2EBC6A330055D639 /* HomeRankVC.m */; };
|
0477BE002EBC6A330055D639 /* HomeRankVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0477BDFF2EBC6A330055D639 /* HomeRankVC.m */; };
|
||||||
0477BE042EBC83130055D639 /* HomeMainVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0477BE032EBC83130055D639 /* HomeMainVC.m */; };
|
0477BE042EBC83130055D639 /* HomeMainVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0477BE032EBC83130055D639 /* HomeMainVC.m */; };
|
||||||
0477BEA22EBCF0000055D639 /* KBTopImageButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 0477BEA12EBCF0000055D639 /* KBTopImageButton.m */; };
|
0477BEA22EBCF0000055D639 /* KBTopImageButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 0477BEA12EBCF0000055D639 /* KBTopImageButton.m */; };
|
||||||
04791F8E2ED469C0004E8522 /* KBHostAppLauncher.m in Sources */ = {isa = PBXBuildFile; fileRef = 04791F8D2ED469C0004E8522 /* KBHostAppLauncher.m */; };
|
|
||||||
04791F8F2ED469C0004E8522 /* KBHostAppLauncher.m in Sources */ = {isa = PBXBuildFile; fileRef = 04791F8D2ED469C0004E8522 /* KBHostAppLauncher.m */; };
|
04791F8F2ED469C0004E8522 /* KBHostAppLauncher.m in Sources */ = {isa = PBXBuildFile; fileRef = 04791F8D2ED469C0004E8522 /* KBHostAppLauncher.m */; };
|
||||||
04791F922ED48010004E8522 /* KBNoticeVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 04791F912ED48010004E8522 /* KBNoticeVC.m */; };
|
04791F922ED48010004E8522 /* KBNoticeVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 04791F912ED48010004E8522 /* KBNoticeVC.m */; };
|
||||||
04791F952ED48028004E8522 /* KBFeedBackVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 04791F942ED48028004E8522 /* KBFeedBackVC.m */; };
|
04791F952ED48028004E8522 /* KBFeedBackVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 04791F942ED48028004E8522 /* KBFeedBackVC.m */; };
|
||||||
@@ -312,6 +310,7 @@
|
|||||||
A1B2C9032FBD000100000001 /* KBBackspaceLongPressHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C9022FBD000100000001 /* KBBackspaceLongPressHandler.m */; };
|
A1B2C9032FBD000100000001 /* KBBackspaceLongPressHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C9022FBD000100000001 /* KBBackspaceLongPressHandler.m */; };
|
||||||
A1B2C9052FBD000200000001 /* KBBackspaceUndoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C9042FBD000200000001 /* KBBackspaceUndoManager.m */; };
|
A1B2C9052FBD000200000001 /* KBBackspaceUndoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C9042FBD000200000001 /* KBBackspaceUndoManager.m */; };
|
||||||
A1B2C9092FBD000200000005 /* KBInputBufferManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C9082FBD000200000004 /* KBInputBufferManager.m */; };
|
A1B2C9092FBD000200000005 /* KBInputBufferManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C9082FBD000200000004 /* KBInputBufferManager.m */; };
|
||||||
|
A1B2C90C2FBD000200000008 /* KBExtensionAppLauncher.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C90B2FBD000200000007 /* KBExtensionAppLauncher.m */; };
|
||||||
A1B2C9262FC9000100000001 /* KBChatMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C9212FC9000100000001 /* KBChatMessage.m */; };
|
A1B2C9262FC9000100000001 /* KBChatMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C9212FC9000100000001 /* KBChatMessage.m */; };
|
||||||
A1B2C9272FC9000100000001 /* KBChatMessageCell.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C9232FC9000100000001 /* KBChatMessageCell.m */; };
|
A1B2C9272FC9000100000001 /* KBChatMessageCell.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C9232FC9000100000001 /* KBChatMessageCell.m */; };
|
||||||
A1B2C9282FC9000100000001 /* KBChatPanelView.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C9252FC9000100000001 /* KBChatPanelView.m */; };
|
A1B2C9282FC9000100000001 /* KBChatPanelView.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C9252FC9000100000001 /* KBChatPanelView.m */; };
|
||||||
@@ -900,6 +899,8 @@
|
|||||||
A1B2C9042FBD000200000001 /* KBBackspaceUndoManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBBackspaceUndoManager.m; sourceTree = "<group>"; };
|
A1B2C9042FBD000200000001 /* KBBackspaceUndoManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBBackspaceUndoManager.m; sourceTree = "<group>"; };
|
||||||
A1B2C9072FBD000200000003 /* KBInputBufferManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBInputBufferManager.h; sourceTree = "<group>"; };
|
A1B2C9072FBD000200000003 /* KBInputBufferManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBInputBufferManager.h; sourceTree = "<group>"; };
|
||||||
A1B2C9082FBD000200000004 /* KBInputBufferManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBInputBufferManager.m; sourceTree = "<group>"; };
|
A1B2C9082FBD000200000004 /* KBInputBufferManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBInputBufferManager.m; sourceTree = "<group>"; };
|
||||||
|
A1B2C90A2FBD000200000006 /* KBExtensionAppLauncher.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBExtensionAppLauncher.h; sourceTree = "<group>"; };
|
||||||
|
A1B2C90B2FBD000200000007 /* KBExtensionAppLauncher.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBExtensionAppLauncher.m; sourceTree = "<group>"; };
|
||||||
A1B2C9202FC9000100000001 /* KBChatMessage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBChatMessage.h; sourceTree = "<group>"; };
|
A1B2C9202FC9000100000001 /* KBChatMessage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBChatMessage.h; sourceTree = "<group>"; };
|
||||||
A1B2C9212FC9000100000001 /* KBChatMessage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBChatMessage.m; sourceTree = "<group>"; };
|
A1B2C9212FC9000100000001 /* KBChatMessage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBChatMessage.m; sourceTree = "<group>"; };
|
||||||
A1B2C9222FC9000100000001 /* KBChatMessageCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBChatMessageCell.h; sourceTree = "<group>"; };
|
A1B2C9222FC9000100000001 /* KBChatMessageCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBChatMessageCell.h; sourceTree = "<group>"; };
|
||||||
@@ -961,7 +962,6 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
0450AB682EF0443E00B6AF06 /* OrderedCollections in Frameworks */,
|
|
||||||
ECC9EE02174D86E8D792472F /* Pods_keyBoard.framework in Frameworks */,
|
ECC9EE02174D86E8D792472F /* Pods_keyBoard.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@@ -1335,6 +1335,8 @@
|
|||||||
A1B2C9042FBD000200000001 /* KBBackspaceUndoManager.m */,
|
A1B2C9042FBD000200000001 /* KBBackspaceUndoManager.m */,
|
||||||
A1B2C9072FBD000200000003 /* KBInputBufferManager.h */,
|
A1B2C9072FBD000200000003 /* KBInputBufferManager.h */,
|
||||||
A1B2C9082FBD000200000004 /* KBInputBufferManager.m */,
|
A1B2C9082FBD000200000004 /* KBInputBufferManager.m */,
|
||||||
|
A1B2C90A2FBD000200000006 /* KBExtensionAppLauncher.h */,
|
||||||
|
A1B2C90B2FBD000200000007 /* KBExtensionAppLauncher.m */,
|
||||||
);
|
);
|
||||||
path = Utils;
|
path = Utils;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -2370,7 +2372,6 @@
|
|||||||
mainGroup = 727EC74A2EAF848B00B36487;
|
mainGroup = 727EC74A2EAF848B00B36487;
|
||||||
minimizedProjectReferenceProxies = 1;
|
minimizedProjectReferenceProxies = 1;
|
||||||
packageReferences = (
|
packageReferences = (
|
||||||
0450AB662EF043C000B6AF06 /* XCRemoteSwiftPackageReference "swift-collections" */,
|
|
||||||
);
|
);
|
||||||
preferredProjectObjectVersion = 77;
|
preferredProjectObjectVersion = 77;
|
||||||
productRefGroup = 727EC7542EAF848B00B36487 /* Products */;
|
productRefGroup = 727EC7542EAF848B00B36487 /* Products */;
|
||||||
@@ -2558,7 +2559,6 @@
|
|||||||
04FEDC122F00010000999999 /* KBKeyboardSubscriptionView.m in Sources */,
|
04FEDC122F00010000999999 /* KBKeyboardSubscriptionView.m in Sources */,
|
||||||
04FEDC322F00030000999999 /* KBKeyboardSubscriptionFeatureItemView.m in Sources */,
|
04FEDC322F00030000999999 /* KBKeyboardSubscriptionFeatureItemView.m in Sources */,
|
||||||
04FEDC422F00040000999999 /* KBKeyboardSubscriptionFeatureMarqueeView.m in Sources */,
|
04FEDC422F00040000999999 /* KBKeyboardSubscriptionFeatureMarqueeView.m in Sources */,
|
||||||
04791F8E2ED469C0004E8522 /* KBHostAppLauncher.m in Sources */,
|
|
||||||
049FB23B2EC4766700FAB05D /* KBFunctionTagListView.m in Sources */,
|
049FB23B2EC4766700FAB05D /* KBFunctionTagListView.m in Sources */,
|
||||||
049FB23C2EC4766700FAB05D /* KBStreamOverlayView.m in Sources */,
|
049FB23C2EC4766700FAB05D /* KBStreamOverlayView.m in Sources */,
|
||||||
049FB22F2EC34EB900FAB05D /* KBStreamTextView.m in Sources */,
|
049FB22F2EC34EB900FAB05D /* KBStreamTextView.m in Sources */,
|
||||||
@@ -2566,6 +2566,7 @@
|
|||||||
A1B2C9032FBD000100000001 /* KBBackspaceLongPressHandler.m in Sources */,
|
A1B2C9032FBD000100000001 /* KBBackspaceLongPressHandler.m in Sources */,
|
||||||
A1B2C9052FBD000200000001 /* KBBackspaceUndoManager.m in Sources */,
|
A1B2C9052FBD000200000001 /* KBBackspaceUndoManager.m in Sources */,
|
||||||
A1B2C9092FBD000200000005 /* KBInputBufferManager.m in Sources */,
|
A1B2C9092FBD000200000005 /* KBInputBufferManager.m in Sources */,
|
||||||
|
A1B2C90C2FBD000200000008 /* KBExtensionAppLauncher.m in Sources */,
|
||||||
049FB23F2EC4B6EF00FAB05D /* KBULBridgeNotification.m in Sources */,
|
049FB23F2EC4B6EF00FAB05D /* KBULBridgeNotification.m in Sources */,
|
||||||
04791F992ED49CE7004E8522 /* KBFont.m in Sources */,
|
04791F992ED49CE7004E8522 /* KBFont.m in Sources */,
|
||||||
04FC956D2EB054B7007BD342 /* KBKeyboardView.m in Sources */,
|
04FC956D2EB054B7007BD342 /* KBKeyboardView.m in Sources */,
|
||||||
@@ -2886,7 +2887,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.loveKey.nyx.CustomKeyboard;
|
PRODUCT_BUNDLE_IDENTIFIER = com.loveKey.nyx.CustomKeyboard;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
@@ -2920,7 +2921,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.loveKey.nyx.CustomKeyboard;
|
PRODUCT_BUNDLE_IDENTIFIER = com.loveKey.nyx.CustomKeyboard;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
@@ -3180,24 +3181,6 @@
|
|||||||
};
|
};
|
||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
|
|
||||||
/* Begin XCRemoteSwiftPackageReference section */
|
|
||||||
0450AB662EF043C000B6AF06 /* XCRemoteSwiftPackageReference "swift-collections" */ = {
|
|
||||||
isa = XCRemoteSwiftPackageReference;
|
|
||||||
repositoryURL = "https://github.com/apple/swift-collections.git";
|
|
||||||
requirement = {
|
|
||||||
kind = upToNextMajorVersion;
|
|
||||||
minimumVersion = 1.3.0;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
/* End XCRemoteSwiftPackageReference section */
|
|
||||||
|
|
||||||
/* Begin XCSwiftPackageProductDependency section */
|
|
||||||
0450AB672EF0443E00B6AF06 /* OrderedCollections */ = {
|
|
||||||
isa = XCSwiftPackageProductDependency;
|
|
||||||
package = 0450AB662EF043C000B6AF06 /* XCRemoteSwiftPackageReference "swift-collections" */;
|
|
||||||
productName = OrderedCollections;
|
|
||||||
};
|
|
||||||
/* End XCSwiftPackageProductDependency section */
|
|
||||||
};
|
};
|
||||||
rootObject = 727EC74B2EAF848B00B36487 /* Project object */;
|
rootObject = 727EC74B2EAF848B00B36487 /* Project object */;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
<RemoteRunnable
|
<RemoteRunnable
|
||||||
runnableDebuggingMode = "0"
|
runnableDebuggingMode = "0"
|
||||||
BundleIdentifier = "com.loveKey.nyx"
|
BundleIdentifier = "com.loveKey.nyx"
|
||||||
RemotePath = "/var/containers/Bundle/Application/E51DCFA2-A182-4B31-8A45-BCCF663ADCAA/keyBoard.app">
|
RemotePath = "/var/containers/Bundle/Application/2983EA21-E95E-41B4-BE99-C7ACBD71D2AF/keyBoard.app">
|
||||||
</RemoteRunnable>
|
</RemoteRunnable>
|
||||||
<MacroExpansion>
|
<MacroExpansion>
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"originHash" : "51f90653b2c9f9f7064c0d52159b40bf7d222e5f314be23e62fe28520fec03db",
|
|
||||||
"pins" : [
|
|
||||||
{
|
|
||||||
"identity" : "swift-collections",
|
|
||||||
"kind" : "remoteSourceControl",
|
|
||||||
"location" : "https://github.com/apple/swift-collections.git",
|
|
||||||
"state" : {
|
|
||||||
"revision" : "7b847a3b7008b2dc2f47ca3110d8c782fb2e5c7e",
|
|
||||||
"version" : "1.3.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"version" : 3
|
|
||||||
}
|
|
||||||
@@ -212,6 +212,23 @@ static NSTimeInterval const kKBSubscriptionPrefillTTL = 10 * 60.0;
|
|||||||
[self kb_openAppSettings];
|
[self kb_openAppSettings];
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
if ([path hasPrefix:@"/ul/recharge"]) {
|
||||||
|
// 通知扩展:UL 已被主 App 接收
|
||||||
|
CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(),
|
||||||
|
(__bridge CFStringRef)KBDarwinULHandled,
|
||||||
|
NULL, NULL, true);
|
||||||
|
// 复用 Scheme 处理逻辑,避免重复实现参数解析与跳转
|
||||||
|
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
|
||||||
|
NSURLComponents *schemeComponents = [[NSURLComponents alloc] init];
|
||||||
|
schemeComponents.scheme = @"kbkeyboardAppExtension";
|
||||||
|
schemeComponents.host = @"recharge";
|
||||||
|
schemeComponents.queryItems = components.queryItems;
|
||||||
|
NSURL *schemeURL = schemeComponents.URL;
|
||||||
|
if (schemeURL) {
|
||||||
|
[self application:application openURL:schemeURL options:@{}];
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
if ([path hasPrefix:@"/ul/login"]) {
|
if ([path hasPrefix:@"/ul/login"]) {
|
||||||
// 区分普通登录与“充值”场景:通过 query 中的 entry=recharge 来判断
|
// 区分普通登录与“充值”场景:通过 query 中的 entry=recharge 来判断
|
||||||
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
|
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
|
||||||
@@ -227,9 +244,15 @@ static NSTimeInterval const kKBSubscriptionPrefillTTL = 10 * 60.0;
|
|||||||
(__bridge CFStringRef)KBDarwinULHandled,
|
(__bridge CFStringRef)KBDarwinULHandled,
|
||||||
NULL, NULL, true);
|
NULL, NULL, true);
|
||||||
if ([entry isEqualToString:@"recharge"]) {
|
if ([entry isEqualToString:@"recharge"]) {
|
||||||
// 充值入口:拉起主 App 后进入充值相关页面(目前先做占位提示)
|
// 充值入口:复用 Scheme 处理逻辑(kbkeyboardAppExtension://recharge?...)
|
||||||
// [KBHUD showInfo:@"去充值"];
|
NSURLComponents *schemeComponents = [[NSURLComponents alloc] init];
|
||||||
|
schemeComponents.scheme = @"kbkeyboardAppExtension";
|
||||||
|
schemeComponents.host = @"recharge";
|
||||||
|
schemeComponents.queryItems = components.queryItems;
|
||||||
|
NSURL *schemeURL = schemeComponents.URL;
|
||||||
|
if (schemeURL) {
|
||||||
|
[self application:application openURL:schemeURL options:@{}];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// 默认逻辑:登录
|
// 默认逻辑:登录
|
||||||
[self kb_presentLoginSheetIfNeeded];
|
[self kb_presentLoginSheetIfNeeded];
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#import "KBHUD.h"
|
#import "KBHUD.h"
|
||||||
#import <MBProgressHUD/MBProgressHUD.h>
|
#import <MBProgressHUD/MBProgressHUD.h>
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
#import <TargetConditionals.h>
|
||||||
|
|
||||||
#ifndef KBSCREEN
|
#ifndef KBSCREEN
|
||||||
#define KBSCREEN [UIScreen mainScreen].bounds.size
|
#define KBSCREEN [UIScreen mainScreen].bounds.size
|
||||||
@@ -29,7 +30,7 @@ static __weak UIView *sContainerView = nil; // 缺省承载视图(
|
|||||||
/// 解析当前 HUD 需要附着的宿主视图
|
/// 解析当前 HUD 需要附着的宿主视图
|
||||||
+ (UIView *)kb_resolvedHostView {
|
+ (UIView *)kb_resolvedHostView {
|
||||||
UIView *hostView = sContainerView;
|
UIView *hostView = sContainerView;
|
||||||
#ifndef KB_APP_EXTENSION
|
#if !TARGET_OS_EXTENSION
|
||||||
// App 内退回到 KeyWindow
|
// App 内退回到 KeyWindow
|
||||||
if (!hostView) {
|
if (!hostView) {
|
||||||
UIWindow *win = nil;
|
UIWindow *win = nil;
|
||||||
|
|||||||
@@ -10,7 +10,9 @@
|
|||||||
#import "KBSkinDetailVC.h"
|
#import "KBSkinDetailVC.h"
|
||||||
#import "KBMyHeaderView.h" // 顶部视图独立封装
|
#import "KBMyHeaderView.h" // 顶部视图独立封装
|
||||||
#import "KBMyListCell.h"
|
#import "KBMyListCell.h"
|
||||||
|
#if DEBUG
|
||||||
#import "KBTestVC.h"
|
#import "KBTestVC.h"
|
||||||
|
#endif
|
||||||
#import "KBNoticeVC.h"
|
#import "KBNoticeVC.h"
|
||||||
#import "KBFeedBackVC.h"
|
#import "KBFeedBackVC.h"
|
||||||
#import "KBMyVM.h"
|
#import "KBMyVM.h"
|
||||||
@@ -50,7 +52,9 @@
|
|||||||
@{ @"title": KBLocalized(@"E-mail"), @"icon": @"my_email_icon", @"color": @(0xFF8A65),@"id":@"4" },
|
@{ @"title": KBLocalized(@"E-mail"), @"icon": @"my_email_icon", @"color": @(0xFF8A65),@"id":@"4" },
|
||||||
@{ @"title": KBLocalized(@"Agreement"), @"icon": @"my_agreement_icon", @"color": @(0x4CD964),@"id":@"5" },
|
@{ @"title": KBLocalized(@"Agreement"), @"icon": @"my_agreement_icon", @"color": @(0x4CD964),@"id":@"5" },
|
||||||
@{ @"title": KBLocalized(@"Privacy Policy"), @"icon": @"my_privacy_icon", @"color": @(0x5AC8FA),@"id":@"6" },
|
@{ @"title": KBLocalized(@"Privacy Policy"), @"icon": @"my_privacy_icon", @"color": @(0x5AC8FA),@"id":@"6" },
|
||||||
|
#if DEBUG
|
||||||
@{ @"title": KBLocalized(@"Test"), @"icon": @"", @"color": @(0x5AC8FA),@"id":@"7" },
|
@{ @"title": KBLocalized(@"Test"), @"icon": @"", @"color": @(0x5AC8FA),@"id":@"7" },
|
||||||
|
#endif
|
||||||
|
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
@@ -223,9 +227,11 @@
|
|||||||
}else if ([itemID isEqualToString:@"8"]){
|
}else if ([itemID isEqualToString:@"8"]){
|
||||||
KBConsumptionRecordVC *vc = [[KBConsumptionRecordVC alloc] init];
|
KBConsumptionRecordVC *vc = [[KBConsumptionRecordVC alloc] init];
|
||||||
[self.navigationController pushViewController:vc animated:true];
|
[self.navigationController pushViewController:vc animated:true];
|
||||||
|
#if DEBUG
|
||||||
}else if ([itemID isEqualToString:@"7"]){
|
}else if ([itemID isEqualToString:@"7"]){
|
||||||
KBTestVC *vc = [[KBTestVC alloc] init];
|
KBTestVC *vc = [[KBTestVC alloc] init];
|
||||||
[self.navigationController pushViewController:vc animated:true];
|
[self.navigationController pushViewController:vc animated:true];
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,20 +10,18 @@
|
|||||||
|
|
||||||
// 基础baseUrl
|
// 基础baseUrl
|
||||||
#ifndef KB_BASE_URL
|
#ifndef KB_BASE_URL
|
||||||
#define KB_BASE_URL @"https://m1.apifoxmock.com/m1/5438099-5113192-default/"
|
#define KB_BASE_URL @"https://devcallback.loveamorkey.com/api"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Universal Links 通用链接
|
// Universal Links 通用链接
|
||||||
#ifndef KB_UL_BASE
|
#ifndef KB_UL_BASE
|
||||||
#define KB_UL_BASE @"https://your.domain/ul"
|
#define KB_UL_BASE @"https://app.tknb.net/ul"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define KB_UL_LOGIN KB_UL_BASE @"/login"
|
#define KB_UL_LOGIN KB_UL_BASE @"/login"
|
||||||
#define KB_UL_SETTINGS KB_UL_BASE @"/settings"
|
#define KB_UL_SETTINGS KB_UL_BASE @"/settings"
|
||||||
// 充值入口的通用链接:当前复用 /login 路径,通过 query 区分(避免额外配置 AASA 路径)
|
// 充值入口的通用链接
|
||||||
#define KB_UL_RECHARGE KB_UL_LOGIN
|
#define KB_UL_RECHARGE KB_UL_BASE @"/recharge"
|
||||||
|
|
||||||
#endif /* KBConfig_h */
|
|
||||||
|
|
||||||
// --- 认证/共享钥匙串 配置 ---
|
// --- 认证/共享钥匙串 配置 ---
|
||||||
// 若已在 Capabilities 中启用 Keychain Sharing,并添加访问组:
|
// 若已在 Capabilities 中启用 Keychain Sharing,并添加访问组:
|
||||||
@@ -34,30 +32,9 @@
|
|||||||
#define KB_KEYCHAIN_ACCESS_GROUP @"TN6HHV45BB.com.loveKey.nyx.shared"
|
#define KB_KEYCHAIN_ACCESS_GROUP @"TN6HHV45BB.com.loveKey.nyx.shared"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// --- 设备特性:是否为带刘海机型(iPhone X 及以后异形屏)---
|
// 说明:
|
||||||
// 说明:在 iPhone 12 等机型底部会有 34px 安全区,这里通过安全区来判断是否为“刘海屏”。
|
// - 该头文件同时被主 App 与键盘扩展引用;
|
||||||
// 注意:使用到 UIKit,这里自行引入,避免依赖 PCH 的包含顺序。
|
// - 设备/窗口相关的 UIKit 辅助方法(如 UIApplication.sharedApplication)在扩展中不可用,
|
||||||
#import <UIKit/UIKit.h>
|
// 请放到主 App 的前缀头或具体业务代码中,避免引入扩展不允许的 API。
|
||||||
static inline BOOL KBDeviceHasNotchRuntime(void) {
|
|
||||||
if (@available(iOS 11.0, *)) {
|
|
||||||
UIWindow *window = nil;
|
|
||||||
if (@available(iOS 13.0, *)) {
|
|
||||||
for (UIScene *scene in UIApplication.sharedApplication.connectedScenes) {
|
|
||||||
if (scene.activationState == UISceneActivationStateForegroundActive && [scene isKindOfClass:[UIWindowScene class]]) {
|
|
||||||
UIWindowScene *ws = (UIWindowScene *)scene;
|
|
||||||
for (UIWindow *w in ws.windows) { if (w.isKeyWindow) { window = w; break; } }
|
|
||||||
if (window) { break; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!window) { window = UIApplication.sharedApplication.windows.firstObject; }
|
|
||||||
} else {
|
|
||||||
window = UIApplication.sharedApplication.keyWindow;
|
|
||||||
}
|
|
||||||
return window.safeAreaInsets.bottom > 0.0;
|
|
||||||
}
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef KB_DEVICE_HAS_NOTCH
|
#endif /* KBConfig_h */
|
||||||
#define KB_DEVICE_HAS_NOTCH (KBDeviceHasNotchRuntime())
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -18,8 +18,10 @@
|
|||||||
<key>NSAppTransportSecurity</key>
|
<key>NSAppTransportSecurity</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSAllowsArbitraryLoads</key>
|
<key>NSAllowsArbitraryLoads</key>
|
||||||
<true/>
|
<false/>
|
||||||
</dict>
|
</dict>
|
||||||
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
|
<string>需要使用麦克风进行语音输入</string>
|
||||||
<key>UIDesignRequiresCompatibility</key>
|
<key>UIDesignRequiresCompatibility</key>
|
||||||
<true/>
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
|
|||||||
@@ -10,20 +10,18 @@
|
|||||||
|
|
||||||
// 基础baseUrl
|
// 基础baseUrl
|
||||||
#ifndef KB_BASE_URL
|
#ifndef KB_BASE_URL
|
||||||
#define KB_BASE_URL @"https://m1.apifoxmock.com/m1/5438099-5113192-default/"
|
#define KB_BASE_URL @"https://devcallback.loveamorkey.com/api"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Universal Links 通用链接
|
// Universal Links 通用链接
|
||||||
#ifndef KB_UL_BASE
|
#ifndef KB_UL_BASE
|
||||||
#define KB_UL_BASE @"https://your.domain/ul"
|
#define KB_UL_BASE @"https://app.tknb.net/ul"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define KB_UL_LOGIN KB_UL_BASE @"/login"
|
#define KB_UL_LOGIN KB_UL_BASE @"/login"
|
||||||
#define KB_UL_SETTINGS KB_UL_BASE @"/settings"
|
#define KB_UL_SETTINGS KB_UL_BASE @"/settings"
|
||||||
// 充值入口的通用链接:当前复用 /login 路径,通过 query 区分(避免额外配置 AASA 路径)
|
// 充值入口的通用链接
|
||||||
#define KB_UL_RECHARGE KB_UL_LOGIN
|
#define KB_UL_RECHARGE KB_UL_BASE @"/recharge"
|
||||||
|
|
||||||
#endif /* KBConfig_h */
|
|
||||||
|
|
||||||
// --- 认证/共享钥匙串 配置 ---
|
// --- 认证/共享钥匙串 配置 ---
|
||||||
// 若已在 Capabilities 中启用 Keychain Sharing,并添加访问组:
|
// 若已在 Capabilities 中启用 Keychain Sharing,并添加访问组:
|
||||||
@@ -34,30 +32,9 @@
|
|||||||
#define KB_KEYCHAIN_ACCESS_GROUP @"TN6HHV45BB.com.loveKey.nyx.shared"
|
#define KB_KEYCHAIN_ACCESS_GROUP @"TN6HHV45BB.com.loveKey.nyx.shared"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// --- 设备特性:是否为带刘海机型(iPhone X 及以后异形屏)---
|
// 说明:
|
||||||
// 说明:在 iPhone 12 等机型底部会有 34px 安全区,这里通过安全区来判断是否为“刘海屏”。
|
// - 该头文件同时被主 App 与键盘扩展引用;
|
||||||
// 注意:使用到 UIKit,这里自行引入,避免依赖 PCH 的包含顺序。
|
// - 设备/窗口相关的 UIKit 辅助方法(如 UIApplication.sharedApplication)在扩展中不可用,
|
||||||
#import <UIKit/UIKit.h>
|
// 请放到主 App 的前缀头或具体业务代码中,避免引入扩展不允许的 API。
|
||||||
static inline BOOL KBDeviceHasNotchRuntime(void) {
|
|
||||||
if (@available(iOS 11.0, *)) {
|
|
||||||
UIWindow *window = nil;
|
|
||||||
if (@available(iOS 13.0, *)) {
|
|
||||||
for (UIScene *scene in UIApplication.sharedApplication.connectedScenes) {
|
|
||||||
if (scene.activationState == UISceneActivationStateForegroundActive && [scene isKindOfClass:[UIWindowScene class]]) {
|
|
||||||
UIWindowScene *ws = (UIWindowScene *)scene;
|
|
||||||
for (UIWindow *w in ws.windows) { if (w.isKeyWindow) { window = w; break; } }
|
|
||||||
if (window) { break; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!window) { window = UIApplication.sharedApplication.windows.firstObject; }
|
|
||||||
} else {
|
|
||||||
window = UIApplication.sharedApplication.keyWindow;
|
|
||||||
}
|
|
||||||
return window.safeAreaInsets.bottom > 0.0;
|
|
||||||
}
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef KB_DEVICE_HAS_NOTCH
|
#endif /* KBConfig_h */
|
||||||
#define KB_DEVICE_HAS_NOTCH (KBDeviceHasNotchRuntime())
|
|
||||||
#endif
|
|
||||||
|
|||||||
Reference in New Issue
Block a user