This commit is contained in:
2025-10-30 20:23:34 +08:00
parent 9af91cc4bc
commit 247a87891e
8 changed files with 302 additions and 17 deletions

View File

@@ -24,6 +24,9 @@ static CGFloat KEYBOARDHEIGHT = 256 + 20;
@implementation KeyboardViewController
{
BOOL _kb_didTriggerLoginDeepLinkOnce;
}
- (void)viewDidLoad {
[super viewDidLoad];
@@ -72,16 +75,16 @@ static CGFloat KEYBOARDHEIGHT = 256 + 20;
/// / keyBoardMainView /
- (void)showSettingView:(BOOL)show {
if (show) {
// if (!self.settingView) {
self.settingView = [[KBSettingView alloc] init];
self.settingView.hidden = YES;
[self.view addSubview:self.settingView];
[self.settingView mas_makeConstraints:^(MASConstraintMaker *make) {
//
make.edges.equalTo(self.keyBoardMainView);
}];
[self.settingView.backButton addTarget:self action:@selector(onTapSettingsBack) forControlEvents:UIControlEventTouchUpInside];
// }
// if (!self.settingView) {
self.settingView = [[KBSettingView alloc] init];
self.settingView.hidden = YES;
[self.view addSubview:self.settingView];
[self.settingView mas_makeConstraints:^(MASConstraintMaker *make) {
//
make.edges.equalTo(self.keyBoardMainView);
}];
[self.settingView.backButton addTarget:self action:@selector(onTapSettingsBack) forControlEvents:UIControlEventTouchUpInside];
// }
[self.view bringSubviewToFront:self.settingView];
// keyBoardMainView self.view
[self.view layoutIfNeeded];
@@ -183,4 +186,23 @@ static CGFloat KEYBOARDHEIGHT = 256 + 20;
[self showSettingView:NO];
}
// App App
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (!_kb_didTriggerLoginDeepLinkOnce) {
_kb_didTriggerLoginDeepLinkOnce = YES;
[self kb_tryOpenContainerForLoginIfNeeded];
}
}
- (void)kb_tryOpenContainerForLoginIfNeeded {
NSURL *url = [NSURL URLWithString:@"kbkeyboard://login?src=keyboard"];
if (!url) return;
__weak typeof(self) weakSelf = self;
[self.extensionContext openURL:url completionHandler:^(__unused BOOL success) {
// 使
__unused typeof(weakSelf) selfStrong = weakSelf;
}];
}
@end

View File

@@ -10,6 +10,7 @@
#import "KBFunctionPasteView.h"
#import "KBFunctionTagCell.h"
#import "Masonry.h"
#import <MBProgressHUD.h>
static NSString * const kKBFunctionTagCellId = @"KBFunctionTagCellId";
@@ -160,6 +161,26 @@ static NSString * const kKBFunctionTagCellId = @"KBFunctionTagCellId";
return 12.0;
}
// App App
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
UIInputViewController *ivc = [self findInputViewController];
if (!ivc) return;
NSString *title = (indexPath.item < self.itemsInternal.count) ? self.itemsInternal[indexPath.item] : @"";
NSString *encodedTitle = [title stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]] ?: @"";
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"kbkeyboard://login?src=functionView&index=%ld&title=%@", (long)indexPath.item, encodedTitle]];
if (!url) return;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[ivc.extensionContext openURL:url completionHandler:^(BOOL success) {
if (!success) {
NSLog(@"[KB] openURL failed. Likely Full Access is OFF. 请到 设置>通用>键盘>键盘>你的键盘 开启“允许完全访问”。");
}
}];
});
}
#pragma mark - Button Actions
- (void)onTapPaste {

View File

@@ -36,6 +36,7 @@
04FC95E92EB23B67007BD342 /* KBNetworkManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95E72EB23B67007BD342 /* KBNetworkManager.m */; };
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 */; };
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 */; };
@@ -131,6 +132,8 @@
04FC95F22EB339C1007BD342 /* AppleSignInManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppleSignInManager.h; sourceTree = "<group>"; };
04FC95F32EB339C1007BD342 /* AppleSignInManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppleSignInManager.m; sourceTree = "<group>"; };
04FC95F52EB33B52007BD342 /* keyBoard.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = keyBoard.entitlements; sourceTree = "<group>"; };
04FC96112EB34E00007BD342 /* KBLoginSheetViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBLoginSheetViewController.h; sourceTree = "<group>"; };
04FC96122EB34E00007BD342 /* KBLoginSheetViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBLoginSheetViewController.m; sourceTree = "<group>"; };
04FC96FE2EB30A00007BD342 /* KBGuideTopCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBGuideTopCell.h; sourceTree = "<group>"; };
04FC96FF2EB30A00007BD342 /* KBGuideTopCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBGuideTopCell.m; sourceTree = "<group>"; };
04FC97012EB30A00007BD342 /* KBGuideKFCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBGuideKFCell.h; sourceTree = "<group>"; };
@@ -487,6 +490,8 @@
children = (
04FC95EF2EB339A7007BD342 /* LoginViewController.h */,
04FC95F02EB339A7007BD342 /* LoginViewController.m */,
04FC96112EB34E00007BD342 /* KBLoginSheetViewController.h */,
04FC96122EB34E00007BD342 /* KBLoginSheetViewController.m */,
);
path = VC;
sourceTree = "<group>";
@@ -756,6 +761,7 @@
043FBCD22EAF97630036AFE1 /* KBPermissionViewController.m in Sources */,
04C6EABE2EAF86530089C901 /* AppDelegate.m in Sources */,
04FC95F12EB339A7007BD342 /* LoginViewController.m in Sources */,
04FC96142EB34E00007BD342 /* KBLoginSheetViewController.m in Sources */,
04FC95D72EB1EA16007BD342 /* BaseTableView.m in Sources */,
04FC95D82EB1EA16007BD342 /* BaseCell.m in Sources */,
04FC95C92EB1E4C9007BD342 /* BaseNavigationController.m in Sources */,
@@ -874,7 +880,15 @@
GCC_PREFIX_HEADER = keyBoard/KeyBoardPrefixHeader.pch;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = keyBoard/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "我的输入法";
INFOPLIST_KEY_CFBundleURLTypes = (
{
CFBundleURLName = com.keyBoardst.keyboard;
CFBundleURLSchemes = (
kbkeyboard,
);
},
);
INFOPLIST_KEY_CFBundleDisplayName = "YOLO输入法";
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
INFOPLIST_KEY_UIMainStoryboardFile = Main;
@@ -891,9 +905,9 @@
STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
name = Debug;
};
727EC76D2EAF848C00B36487 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 51FE7C4C42C2255B3C1C4128 /* Pods-keyBoard.release.xcconfig */;
@@ -907,7 +921,15 @@
GCC_PREFIX_HEADER = keyBoard/KeyBoardPrefixHeader.pch;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = keyBoard/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "我的输入法";
INFOPLIST_KEY_CFBundleURLTypes = (
{
CFBundleURLName = com.keyBoardst.keyboard;
CFBundleURLSchemes = (
kbkeyboard,
);
},
);
INFOPLIST_KEY_CFBundleDisplayName = "YOLO输入法";
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
INFOPLIST_KEY_UIMainStoryboardFile = Main;

View File

@@ -11,6 +11,8 @@
#import <Bugly/Bugly.h>
#import "BaseTabBarController.h"
#import "LoginViewController.h"
#import "KBLoginSheetViewController.h"
#import "AppleSignInManager.h"
// bundle id target
// PRODUCT_BUNDLE_IDENTIFIER
@@ -44,7 +46,7 @@ static NSString * const kKBKeyboardExtensionBundleId = @"com.keyBoardst.CustomKe
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
LoginViewController *vc = [[LoginViewController alloc] init];
BaseTabBarController *vc = [[BaseTabBarController alloc] init];
self.window.rootViewController = vc;
}
@@ -61,6 +63,32 @@ static NSString * const kKBKeyboardExtensionBundleId = @"com.keyBoardst.CustomKe
return top;
}
#pragma mark - Deep Link
// iOS 9+
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
if (!url) return NO;
if ([[url.scheme lowercaseString] isEqualToString:@"kbkeyboard"]) {
// kbkeyboard://login
if ([[url.host lowercaseString] isEqualToString:@"login"]) {
[self kb_presentLoginSheetIfNeeded];
return YES;
}
return NO;
}
return NO;
}
- (void)kb_presentLoginSheetIfNeeded {
//
BOOL loggedIn = ([AppleSignInManager shared].storedUserIdentifier.length > 0);
if (loggedIn) return;
UIViewController *top = [self kb_topMostViewController];
if (!top) return;
[KBLoginSheetViewController presentIfNeededFrom:top];
}
- (void)kb_presentPermissionIfNeeded
{
BOOL enabled = KBIsKeyboardEnabled();

View File

@@ -0,0 +1,23 @@
//
// KBLoginSheetViewController.h
// keyBoard
//
// A lightweight bottom-sheet style login prompt.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface KBLoginSheetViewController : UIViewController
/// Called when the login finished successfully; sheet will dismiss itself as well.
@property (nonatomic, copy, nullable) void (^onLoginSuccess)(void);
/// Present the sheet from a top most view controller.
+ (void)presentIfNeededFrom:(UIViewController *)presenting;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,154 @@
//
// KBLoginSheetViewController.m
// keyBoard
//
// Bottom sheet asking user to login with Apple ID. Tapping Continue shows LoginViewController.
//
#import "KBLoginSheetViewController.h"
#import "LoginViewController.h"
#import <Masonry/Masonry.h>
@interface KBLoginSheetViewController ()
@property (nonatomic, strong) UIControl *backdrop;
@property (nonatomic, strong) UIView *sheet;
@property (nonatomic, strong) UIButton *checkButton;
@property (nonatomic, strong) UILabel *descLabel;
@property (nonatomic, strong) UIButton *continueButton;
@end
@implementation KBLoginSheetViewController
+ (void)presentIfNeededFrom:(UIViewController *)presenting {
if (!presenting) return;
//
if ([presenting.presentedViewController isKindOfClass:[self class]]) return;
KBLoginSheetViewController *vc = [KBLoginSheetViewController new];
vc.modalPresentationStyle = UIModalPresentationOverFullScreen;
[presenting presentViewController:vc animated:NO completion:nil];
}
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor clearColor];
[self buildUI];
}
- (void)buildUI {
//
self.backdrop = [[UIControl alloc] init];
self.backdrop.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.15];
[self.backdrop addTarget:self action:@selector(dismissSelf) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.backdrop];
[self.backdrop mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.view);
}];
//
self.sheet = [[UIView alloc] init];
self.sheet.backgroundColor = [UIColor whiteColor];
self.sheet.layer.cornerRadius = 12.0;
self.sheet.layer.maskedCorners = kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner; //
self.sheet.layer.masksToBounds = YES;
[self.view addSubview:self.sheet];
[self.sheet mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self.view);
make.bottom.equalTo(self.view.mas_safeAreaLayoutGuideBottom);
make.height.mas_equalTo(160);
}];
// +
self.checkButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.checkButton.layer.cornerRadius = 16;
self.checkButton.layer.borderWidth = 2;
self.checkButton.layer.borderColor = [UIColor colorWithWhite:0.8 alpha:1.0].CGColor;
self.checkButton.backgroundColor = [UIColor whiteColor];
[self.checkButton setTitle:@"" forState:UIControlStateNormal];
[self.checkButton addTarget:self action:@selector(toggleCheck) forControlEvents:UIControlEventTouchUpInside];
self.descLabel = [UILabel new];
self.descLabel.text = @"allow log in with apple id?";
self.descLabel.textColor = [UIColor blackColor];
self.descLabel.font = [UIFont systemFontOfSize:16];
[self.sheet addSubview:self.checkButton];
[self.sheet addSubview:self.descLabel];
[self.checkButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.sheet).offset(28);
make.top.equalTo(self.sheet).offset(18);
make.width.height.mas_equalTo(32);
}];
[self.descLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.checkButton.mas_right).offset(12);
make.centerY.equalTo(self.checkButton.mas_centerY);
make.right.lessThanOrEqualTo(self.sheet).offset(-20);
}];
// Continue
self.continueButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.continueButton.backgroundColor = [UIColor whiteColor];
self.continueButton.layer.cornerRadius = 10;
self.continueButton.layer.borderWidth = 1.0;
self.continueButton.layer.borderColor = [UIColor colorWithWhite:0.8 alpha:1.0].CGColor;
[self.continueButton setTitle:@"Continue" forState:UIControlStateNormal];
[self.continueButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
self.continueButton.titleLabel.font = [UIFont boldSystemFontOfSize:20];
[self.continueButton addTarget:self action:@selector(onContinue) forControlEvents:UIControlEventTouchUpInside];
[self.sheet addSubview:self.continueButton];
[self.continueButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.sheet).offset(28);
make.right.equalTo(self.sheet).offset(-28);
make.height.mas_equalTo(48);
make.top.equalTo(self.checkButton.mas_bottom).offset(18);
}];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
//
CGRect frame = self.sheet.frame;
self.sheet.transform = CGAffineTransformMakeTranslation(0, frame.size.height + 40);
self.backdrop.alpha = 0;
[UIView animateWithDuration:0.22 animations:^{
self.sheet.transform = CGAffineTransformIdentity;
self.backdrop.alpha = 1;
}];
}
- (void)dismissSelf {
[UIView animateWithDuration:0.18 animations:^{
self.sheet.transform = CGAffineTransformMakeTranslation(0, self.sheet.bounds.size.height + 40);
self.backdrop.alpha = 0;
} completion:^(BOOL finished) {
[self dismissViewControllerAnimated:NO completion:nil];
}];
}
- (void)toggleCheck {
self.checkButton.selected = !self.checkButton.selected;
if (self.checkButton.selected) {
self.checkButton.backgroundColor = [UIColor colorWithRed:0.22 green:0.49 blue:0.96 alpha:1.0];
self.checkButton.layer.borderColor = self.checkButton.backgroundColor.CGColor;
} else {
self.checkButton.backgroundColor = [UIColor whiteColor];
self.checkButton.layer.borderColor = [UIColor colorWithWhite:0.8 alpha:1.0].CGColor;
}
}
- (void)onContinue {
// Apple
LoginViewController *login = [LoginViewController new];
__weak typeof(self) weakSelf = self;
login.onLoginSuccess = ^(NSDictionary * _Nonnull userInfo) {
__strong typeof(weakSelf) self = weakSelf; if (!self) return;
//
[self dismissViewControllerAnimated:YES completion:^{
if (self.onLoginSuccess) self.onLoginSuccess();
[self dismissSelf];
}];
};
login.modalPresentationStyle = UIModalPresentationPageSheet;
[self presentViewController:login animated:YES completion:nil];
}
@end

View File

@@ -85,8 +85,12 @@ static NSString * const kKBAppleUserIdentifierKey = @"com.company.keyboard.apple
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0)) {
if (@available(iOS 13.0, *)) {
ASAuthorizationAppleIDCredential *credential = authorization.credential;
// userIdentifier
// NSString *userID = credential.user; //
// / App userIdentifier
//
NSString *userID = credential.user ?: @"";
if (userID.length > 0) {
[self.class keychainSave:kKBAppleUserIdentifierKey value:userID];
}
if (self.completion) {
self.completion(credential, nil);
}

View File

@@ -7,5 +7,16 @@
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>com.keyBoardst.keyboard</string>
<key>CFBundleURLSchemes</key>
<array>
<string>kbkeyboard</string>
</array>
</dict>
</array>
</dict>
</plist>