From 7c0af05d21ca37d444c75a50eeb4e662a782ee3b Mon Sep 17 00:00:00 2001 From: wrapping-2000 Date: Tue, 1 Aug 2023 20:11:05 +0800 Subject: [PATCH] feat: Support WeChat iOS native third-party login. --- ios/Classes/CasdoorFlutterSdkPlugin.m | 29 --- ios/Classes/OcCasdoorFlutterSdkPlugin.h | 18 ++ ios/Classes/OcCasdoorFlutterSdkPlugin.m | 202 ++++++++++++++++++ .../SwiftCasdoorFlutterSdkPlugin.swift | 121 ----------- ios/casdoor_flutter_sdk.podspec | 83 ++++++- ios/wechat_setup.rb | 154 +++++++++++++ lib/casdoor.dart | 2 +- lib/casdoor_flutter_sdk_oauth.dart | 7 + 8 files changed, 464 insertions(+), 152 deletions(-) delete mode 100644 ios/Classes/CasdoorFlutterSdkPlugin.m create mode 100644 ios/Classes/OcCasdoorFlutterSdkPlugin.h create mode 100644 ios/Classes/OcCasdoorFlutterSdkPlugin.m delete mode 100644 ios/Classes/SwiftCasdoorFlutterSdkPlugin.swift create mode 100644 ios/wechat_setup.rb diff --git a/ios/Classes/CasdoorFlutterSdkPlugin.m b/ios/Classes/CasdoorFlutterSdkPlugin.m deleted file mode 100644 index f963f6d..0000000 --- a/ios/Classes/CasdoorFlutterSdkPlugin.m +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2022 The casbin Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#import "CasdoorFlutterSdkPlugin.h" -#if __has_include() -#import -#else -// Support project import fallback if the generated compatibility header -// is not copied when this plugin is created as a library. -// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816 -#import "casdoor_flutter_sdk-Swift.h" -#endif - -@implementation CasdoorFlutterSdkPlugin -+ (void)registerWithRegistrar:(NSObject*)registrar { - [SwiftCasdoorFlutterSdkPlugin registerWithRegistrar:registrar]; -} -@end diff --git a/ios/Classes/OcCasdoorFlutterSdkPlugin.h b/ios/Classes/OcCasdoorFlutterSdkPlugin.h new file mode 100644 index 0000000..c601e66 --- /dev/null +++ b/ios/Classes/OcCasdoorFlutterSdkPlugin.h @@ -0,0 +1,18 @@ +// Copyright 2022 The casbin Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +@interface CasdoorFlutterSdkPlugin : NSObject +@end \ No newline at end of file diff --git a/ios/Classes/OcCasdoorFlutterSdkPlugin.m b/ios/Classes/OcCasdoorFlutterSdkPlugin.m new file mode 100644 index 0000000..906997f --- /dev/null +++ b/ios/Classes/OcCasdoorFlutterSdkPlugin.m @@ -0,0 +1,202 @@ +// Copyright 2022 The casbin Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import +#import "CasdoorFlutterSdkPlugin.h" +#import +#import +#import +#import +@import WebKit; + +#define APP_ID @"wx049c70e6c2027b0b" +#define UNIVERSAL_LINK @"https://testdomain.com" + + +typedef void (^AuthResultCallback)(NSString *); +@interface CasdoorFlutterSdkPlugin () +@property (nonatomic, strong) WKWebView *webView; +@property (nonatomic, copy) NSString *callbackURLScheme; +@property (nonatomic, copy) AuthResultCallback authResultCallback; +@end + +@implementation CasdoorFlutterSdkPlugin + + + + ++ (void)registerWithRegistrar:(NSObject*)registrar { + FlutterMethodChannel* channel = [FlutterMethodChannel + methodChannelWithName:@"casdoor_flutter_sdk" + binaryMessenger:[registrar messenger]]; + CasdoorFlutterSdkPlugin* instance = [[CasdoorFlutterSdkPlugin alloc] init]; + [registrar addMethodCallDelegate:instance channel:channel]; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _webView = [[WKWebView alloc] init]; + _webView.navigationDelegate = self; + } + return self; +} + +- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { + if ([call.method isEqualToString:@"authenticate"]) { + NSDictionary *arguments = call.arguments; + NSString *urlString = arguments[@"url"]; + NSURL *url = [NSURL URLWithString:urlString]; + NSString *callbackURLScheme = arguments[@"callbackUrlScheme"]; + + self.callbackURLScheme = callbackURLScheme; + + __weak typeof(self) weakSelf = self; + self.authResultCallback = ^(NSString *authResult) { + result(authResult); + }; + + UIViewController *viewController = [[[UIApplication sharedApplication] delegate] window].rootViewController; + self.webView.frame = viewController.view.bounds; + self.webView.translatesAutoresizingMaskIntoConstraints = NO; + [viewController.view addSubview:self.webView]; + [viewController.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-0-[view]-0-|" options:0 metrics:nil views:@{@"view": self.webView}]]; + [viewController.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[view]-0-|" options:0 metrics:nil views:@{@"view": self.webView}]]; + + NSURLRequest *req = [NSURLRequest requestWithURL:url]; + dispatch_async(dispatch_get_main_queue(), ^{ + [weakSelf.webView loadRequest:req]; + }); + } else if ([call.method isEqualToString:@"cleanUpDanglingCalls"]) { + result(nil); + } else if ([call.method isEqualToString:@"getPlatformVersion"]) { + NSString *version = [NSString stringWithFormat:@"iOS %@", [[NSProcessInfo processInfo] operatingSystemVersionString]]; + result(version); + } else if ([call.method isEqualToString:@"registerWXApi"]) { + NSDictionary *arguments = call.arguments; + NSString *app_id = arguments[@"app_id"]; + NSString *universal_link = arguments[@"universal_link"]; + // register WeChat + BOOL isWeChatRegistered = [WXApi registerApp:app_id universalLink:universal_link]; + NSLog(@"Is WeChat Registered: %@", isWeChatRegistered ? @"YES" : @"NO"); + }else { + result(FlutterMethodNotImplemented); + } +} + +- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url { + return [WXApi handleOpenURL:url delegate:self]; +} + +- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { + return [WXApi handleOpenURL:url delegate:self]; +} + +- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void(^)(NSArray> * __nullable restorableObjects))restorationHandler { + return [WXApi handleOpenUniversalLink:userActivity delegate:self]; +} + +-(void) onReq:(BaseReq*)reqonReq { + +} + +-(void) onResp:(BaseResp*)resp { + /* + enum WXErrCode { + WXSuccess = 0, 成功 + WXErrCodeCommon = -1, 普通错误类型 + WXErrCodeUserCancel = -2, 用户点击取消并返回 + WXErrCodeSentFail = -3, 发送失败 + WXErrCodeAuthDeny = -4, 授权失败 + WXErrCodeUnsupport = -5, 微信不支持 + }; + */ + if (resp.errCode == 0) { //Success + NSLog(@"Login Success."); + SendAuthResp *resp2 = (SendAuthResp *)resp; + NSLog(@"code: %@", resp2.code); + + }else{ //Failed + NSLog(@"error %@", resp.errStr); + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Login failed." message:[NSString stringWithFormat:@"reason: %@", resp.errStr] preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancle" style:UIAlertActionStyleCancel handler:nil]; + UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:@"Confirm" style:UIAlertActionStyleDefault handler:nil]; + + [alertController addAction:cancelAction]; + [alertController addAction:confirmAction]; + + UIViewController *rootViewController = UIApplication.sharedApplication.keyWindow.rootViewController; + [rootViewController presentViewController:alertController animated:YES completion:nil]; + } +} + +#pragma mark - WKNavigationDelegate + +- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { + + NSURL *callbackUrl = navigationAction.request.URL; + if (callbackUrl.scheme && [callbackUrl.scheme isEqualToString:self.callbackURLScheme]) { + + NSLog(@"callbackUrl: %@", callbackUrl); + + self.authResultCallback(callbackUrl.absoluteString); + + decisionHandler(WKNavigationActionPolicyCancel); + [webView removeFromSuperview]; + return; + } else if ([navigationAction.request.URL.absoluteString containsString:@"https://open.weixin.qq.com"]) { + + BOOL isInstalled = [WXApi isWXAppInstalled]; + NSLog(@"Is WeChat Installed: %@", isInstalled ? @"YES" : @"NO"); + if ([WXApi isWXAppInstalled]) { + + // Open the log before register, and you can troubleshoot problems based on the log later +// [WXApi startLogByLevel:WXLogLevelDetail logBlock:^(NSString *log) { +// NSLog(@"WeChatSDK: %@", log); +// }]; +// +// // Call the self-test function +// [WXApi checkUniversalLinkReady:^(WXULCheckStep step, WXCheckULStepResult* result) { +// NSLog(@"%@, %u, %@, %@", @(step), result.success, result.errorInfo, result.suggestion); +// }]; + + SendAuthReq *req = [[SendAuthReq alloc]init]; + req.scope = @"snsapi_userinfo"; + req.state = @"wx_oauth_authorization_state"; + [WXApi sendReq:req completion:nil]; + + + decisionHandler(WKNavigationActionPolicyCancel); + [webView removeFromSuperview]; + }else{ + // If WeChat is not installed, do nothing, use the scan code of the website to log in. + } + + NSLog(@"Clicked on a link containing 'https://open.weixin.qq.com'"); + return; + } else if ([navigationAction.request.URL.absoluteString containsString:@"https://openauth.alipay.com"]) { + // If we click on Alipay as a third-party login, write the implementation part here. +// decisionHandler(WKNavigationActionPolicyCancel); +// [webView removeFromSuperview]; + NSLog(@"Clicked on a link containing 'https://openauth.alipay.com'"); + return; + } + + decisionHandler(WKNavigationActionPolicyAllow); +} + +@end + + diff --git a/ios/Classes/SwiftCasdoorFlutterSdkPlugin.swift b/ios/Classes/SwiftCasdoorFlutterSdkPlugin.swift deleted file mode 100644 index 090b7c4..0000000 --- a/ios/Classes/SwiftCasdoorFlutterSdkPlugin.swift +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2022 The casbin Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import Flutter -import UIKit -import AuthenticationServices -import SafariServices - -public class SwiftCasdoorFlutterSdkPlugin: NSObject, FlutterPlugin { - public static func register(with registrar: FlutterPluginRegistrar) { - let channel = FlutterMethodChannel(name: "casdoor_flutter_sdk", binaryMessenger: registrar.messenger()) - let instance = SwiftCasdoorFlutterSdkPlugin() - registrar.addMethodCallDelegate(instance, channel: channel) - } - - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - if call.method == "authenticate", - let arguments = call.arguments as? Dictionary, - let urlString = arguments["url"] as? String, - let url = URL(string: urlString), - let callbackURLScheme = arguments["callbackUrlScheme"] as? String, - let preferEphemeral = arguments["preferEphemeral"] as? Bool - { - - var sessionToKeepAlive: Any? = nil // if we do not keep the session alive, it will get closed immediately while showing the dialog - let completionHandler = { (url: URL?, err: Error?) in - sessionToKeepAlive = nil - - if let err = err { - if #available(iOS 12, *) { - if case ASWebAuthenticationSessionError.canceledLogin = err { - result(FlutterError(code: "CANCELED", message: "User canceled login", details: nil)) - return - } - } - - if #available(iOS 11, *) { - if case SFAuthenticationError.canceledLogin = err { - result(FlutterError(code: "CANCELED", message: "User canceled login", details: nil)) - return - } - } - - result(FlutterError(code: "EUNKNOWN", message: err.localizedDescription, details: nil)) - return - } - - guard let url = url else { - result(FlutterError(code: "EUNKNOWN", message: "URL was null, but no error provided.", details: nil)) - return - } - - result(url.absoluteString) - } - - if #available(iOS 12, *) { - let session = ASWebAuthenticationSession(url: url, callbackURLScheme: callbackURLScheme, completionHandler: completionHandler) - - if #available(iOS 13, *) { - guard var topController = UIApplication.shared.keyWindow?.rootViewController else { - result(FlutterError.aquireRootViewControllerFailed) - return - } - - while let presentedViewController = topController.presentedViewController { - topController = presentedViewController - } - if let nav = topController as? UINavigationController { - topController = nav.visibleViewController ?? topController - } - - guard let contextProvider = topController as? ASWebAuthenticationPresentationContextProviding else { - result(FlutterError.aquireRootViewControllerFailed) - return - } - session.presentationContextProvider = contextProvider - session.prefersEphemeralWebBrowserSession = preferEphemeral - } - - session.start() - sessionToKeepAlive = session - } else if #available(iOS 11, *) { - let session = SFAuthenticationSession(url: url, callbackURLScheme: callbackURLScheme, completionHandler: completionHandler) - session.start() - sessionToKeepAlive = session - } else { - result(FlutterError(code: "FAILED", message: "This plugin does currently not support iOS lower than iOS 11" , details: nil)) - } - } else if (call.method == "cleanUpDanglingCalls") { - // we do not keep track of old callbacks on iOS, so nothing to do here - result(nil) - } else if (call.method == "getPlatformVersion") { - result("iOS " + ProcessInfo.processInfo.operatingSystemVersionString) - } else { - result(FlutterMethodNotImplemented) - } - } -} -@available(iOS 13, *) -extension FlutterViewController: ASWebAuthenticationPresentationContextProviding { - public func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { - return self.view.window! - } -} - -fileprivate extension FlutterError { - static var aquireRootViewControllerFailed: FlutterError { - return FlutterError(code: "AQUIRE_ROOT_VIEW_CONTROLLER_FAILED", message: "Failed to aquire root view controller" , details: nil) - } -} \ No newline at end of file diff --git a/ios/casdoor_flutter_sdk.podspec b/ios/casdoor_flutter_sdk.podspec index 9322cd8..3b2ca96 100644 --- a/ios/casdoor_flutter_sdk.podspec +++ b/ios/casdoor_flutter_sdk.podspec @@ -2,6 +2,64 @@ # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. # Run `pod lib lint casdoor_flutter_sdk.podspec` to validate before publishing. # + +pubspec = YAML.load_file(File.join('..', 'pubspec.yaml')) +library_version = pubspec['version'].gsub('+', '-') + +current_dir = Dir.pwd +calling_dir = File.dirname(__FILE__) +project_dir = calling_dir.slice(0..(calling_dir.index('/.symlinks'))) +flutter_project_dir = calling_dir.slice(0..(calling_dir.index('/ios/.symlinks'))) + +puts Psych::VERSION +psych_version_gte_500 = Gem::Version.new(Psych::VERSION) >= Gem::Version.new('5.0.0') +if psych_version_gte_500 == true + cfg = YAML.load_file(File.join(flutter_project_dir, 'pubspec.yaml'), aliases: true) +else + cfg = YAML.load_file(File.join(flutter_project_dir, 'pubspec.yaml')) +end + +logging_status = "WECHAT_LOGGING=0" + +if cfg['casdoor_flutter_sdk'] && cfg['casdoor_flutter_sdk']['debug_logging'] == true + logging_status = 'WECHAT_LOGGING=1' +else + logging_status = 'WECHAT_LOGGING=0' +end + +scene_delegate = '' +if cfg['casdoor_flutter_sdk'] && cfg['casdoor_flutter_sdk']['ios'] && cfg['casdoor_flutter_sdk']['ios']['scene_delegate'] == true + scene_delegate = 'SCENE_DELEGATE=1' +else + scene_delegate = '' +end + + +if cfg['casdoor_flutter_sdk'] && cfg['casdoor_flutter_sdk']['ios'] && cfg['casdoor_flutter_sdk']['ios']['no_pay'] == true + sdk_subspec = 'no_pay' +else + sdk_subspec = 'pay' +end +Pod::UI.puts "using sdk with #{sdk_subspec}" + +app_id = nil + +if cfg['casdoor_flutter_sdk'] && cfg['casdoor_flutter_sdk']['app_id'] + app_id = cfg['casdoor_flutter_sdk']['app_id'] +end + + +if cfg['casdoor_flutter_sdk'] && (cfg['casdoor_flutter_sdk']['ios'] && cfg['casdoor_flutter_sdk']['ios']['universal_link']) + universal_link = cfg['casdoor_flutter_sdk']['ios']['universal_link'] + if app_id.nil? + system("ruby #{current_dir}/wechat_setup.rb -u #{universal_link} -p #{project_dir} -n Runner.xcodeproj") + else + system("ruby #{current_dir}/wechat_setup.rb -a #{app_id} -u #{universal_link} -p #{project_dir} -n Runner.xcodeproj") + end +else + abort("required values:[auniversal_link] are missing. Please add them in pubspec.yaml:\ncasdoor_flutter_sdk:\n \nios:\nuniversal_link: https://${applinks domain}/universal_link/${example_app}/wechat/\n") +end + Pod::Spec.new do |s| s.name = 'casdoor_flutter_sdk' s.version = '0.0.1' @@ -15,9 +73,32 @@ A new Flutter project. s.source = { :path => '.' } s.source_files = 'Classes/**/*' s.dependency 'Flutter' - s.platform = :ios, '9.0' + s.platform = :ios, '11.0' + s.static_framework = true + s.default_subspec = sdk_subspec # Flutter.framework does not contain a i386 slice. s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } s.swift_version = '5.0' + + pod_target_xcconfig = { + 'OTHER_LDFLAGS' => '$(inherited) -ObjC -all_load' + } + + s.subspec 'pay' do |sp| + sp.dependency 'WechatOpenSDK-XCFramework','~> 2.0.2' + + pod_target_xcconfig["GCC_PREPROCESSOR_DEFINITIONS"] = "$(inherited) #{logging_status} #{scene_delegate}" + + sp.pod_target_xcconfig = pod_target_xcconfig + end + + s.subspec 'no_pay' do |sp| + sp.dependency 'OpenWeChatSDKNoPay','~> 2.0.2+2' + sp.frameworks = 'CoreGraphics', 'Security', 'WebKit' + sp.libraries = 'c++', 'z', 'sqlite3.0' + pod_target_xcconfig["GCC_PREPROCESSOR_DEFINITIONS"] = "$(inherited) NO_PAY=1 #{logging_status} #{scene_delegate}" + sp.pod_target_xcconfig = pod_target_xcconfig + end + end diff --git a/ios/wechat_setup.rb b/ios/wechat_setup.rb new file mode 100644 index 0000000..92309be --- /dev/null +++ b/ios/wechat_setup.rb @@ -0,0 +1,154 @@ +# +# Reference documentations +# https://github.com/firebase/flutterfire/blob/master/packages/firebase_crashlytics/firebase_crashlytics/ios/crashlytics_add_upload_symbols +# https://github.com/MagicalWater/Base-APP-Env/blob/master/fastlane/actions/xcode_parse.rb +# + +require 'xcodeproj' +require 'plist' +require 'optparse' +require 'uri' + +# Dictionary to hold command line arguments +options_dict = {} + +# Parse command line arguments into options_dict +OptionParser.new do |options| + options.banner = "Setup the Wechat to an Xcode target." + + options.on("-p", "--projectDirectory=DIRECTORY", String, "Directory of the Xcode project") do |dir| + options_dict[:project_dir] = dir + end + + options.on("-n", "--projectName=NAME", String, "Name of the Xcode project (ex: Runner.xcodeproj)") do |name| + options_dict[:project_name] = name + end + + options.on("-a", "--appId=APPID", String, "App ID for Wechat") do |opts| + options_dict[:app_id] = opts + end + + options.on("-u", "--universalLink=UNIVERSALLINK", String, "Universal Link for Wechat") do |opts| + options_dict[:universal_link] = opts + end +end.parse! + +# Minimum required arguments are a project directory and project name +unless (options_dict[:project_dir] and options_dict[:project_name]) + abort("Must provide a project directory and project name.\n") +end + +# Path to the Xcode project to modify +project_path = File.join(options_dict[:project_dir], options_dict[:project_name]) + +unless (File.exist?(project_path)) + abort("Project at #{project_path} does not exist. Please check paths manually.\n"); +end + +# Actually open and modify the project +project = Xcodeproj::Project.open(project_path) +project.targets.each do |target| + if target.name == "Runner" + app_id = options_dict[:app_id] + universal_link = options_dict[:universal_link] + applinks = "applinks:#{URI.parse(universal_link).host}" + + sectionObject = {} + project.objects.each do |object| + if object.uuid == target.uuid + sectionObject = object + break + end + end + sectionObject.build_configurations.each do |config| + infoplist = config.build_settings["INFOPLIST_FILE"] + if !infoplist + abort("INFOPLIST_FILE is not exist\n") + end + infoplistFile = File.join(options_dict[:project_dir], infoplist) + if !File.exist?(infoplistFile) + abort("#{infoplist} is not exist\n") + end + result = Plist.parse_xml(infoplistFile, marshal: false) + if !result + result = {} + end + urlTypes = result["CFBundleURLTypes"] + if !urlTypes + urlTypes = [] + result["CFBundleURLTypes"] = urlTypes + end + isUrlTypeExist = urlTypes.any? { |urlType| urlType["CFBundleURLSchemes"] && (urlType["CFBundleURLSchemes"].include? app_id) } + if !app_id.nil? && !app_id.empty? && !isUrlTypeExist + print("writing app id\n ") + urlTypes << { + "CFBundleTypeRole": "Editor", + "CFBundleURLName": "weixin", + "CFBundleURLSchemes": [ app_id ] + } + File.write(infoplistFile, Plist::Emit.dump(result)) + end + + queriesSchemes = result["LSApplicationQueriesSchemes"] + if !queriesSchemes + queriesSchemes = [] + result["LSApplicationQueriesSchemes"] = queriesSchemes + end + wechatQueriesSchemes = ["weixin", "weixinULAPI", "weixinURLParamsAPI"] + if wechatQueriesSchemes.any? { |queriesScheme| !(queriesSchemes.include? queriesScheme) } + wechatQueriesSchemes.each do |queriesScheme| + if !(queriesSchemes.include? queriesScheme) + queriesSchemes << queriesScheme + end + end + File.write(infoplistFile, Plist::Emit.dump(result)) + end + security = result["NSAppTransportSecurity"] + if !security + security = {} + result["NSAppTransportSecurity"] = security + end + if security["NSAllowsArbitraryLoads"] != true + security["NSAllowsArbitraryLoads"] = true + File.write(infoplistFile, Plist::Emit.dump(result)) + end + if security["NSAllowsArbitraryLoadsInWebContent"] != true + security["NSAllowsArbitraryLoadsInWebContent"] = true + File.write(infoplistFile, Plist::Emit.dump(result)) + end + end + sectionObject.build_configurations.each do |config| + codeSignEntitlements = config.build_settings["CODE_SIGN_ENTITLEMENTS"] + if !codeSignEntitlements + codeSignEntitlements = "Runner/Runner.entitlements" + config.build_settings["CODE_SIGN_ENTITLEMENTS"] = codeSignEntitlements + project.save() + end + codeSignEntitlementsFile = File.join(options_dict[:project_dir], codeSignEntitlements) + if !File.exist?(codeSignEntitlementsFile) + content = Plist::Emit.dump({}) + File.write(codeSignEntitlementsFile, content) + end + runnerTargetMainGroup = project.main_group.find_subpath('Runner', false) + isRefExist = runnerTargetMainGroup.files.any? { |file| file.path.include? File.basename(codeSignEntitlementsFile) } + if !isRefExist + runnerTargetMainGroup.new_reference(File.basename(codeSignEntitlementsFile)) + project.save() + end + result = Plist.parse_xml(codeSignEntitlementsFile, marshal: false) + if !result + result = {} + end + domains = result["com.apple.developer.associated-domains"] + if !domains + domains = [] + result["com.apple.developer.associated-domains"] = domains + end + isApplinksExist = domains.include? applinks + if !isApplinksExist + domains << applinks + File.write(codeSignEntitlementsFile, Plist::Emit.dump(result)) + end + end + end +end diff --git a/lib/casdoor.dart b/lib/casdoor.dart index 6c10884..34d8881 100644 --- a/lib/casdoor.dart +++ b/lib/casdoor.dart @@ -142,7 +142,7 @@ class Casdoor { } Future getUserInfo(String accessToken) async { - return await http.post( + return await http.get( Uri( scheme: parseScheme(), host: parseHost(), diff --git a/lib/casdoor_flutter_sdk_oauth.dart b/lib/casdoor_flutter_sdk_oauth.dart index 94eb51f..6c1221e 100644 --- a/lib/casdoor_flutter_sdk_oauth.dart +++ b/lib/casdoor_flutter_sdk_oauth.dart @@ -38,6 +38,13 @@ class CasdoorOauth { return CasdoorFlutterSdkPlatform.instance.getPlatformVersion(); } + static Future registerWXApi({required String app_id, required String universal_link}) async { + return await _channel.invokeMethod('registerWXApi', { + 'app_id': app_id, + 'universal_link': universal_link, + }) as String; + } + static final _OnAppLifecycleResumeObserver _resumedObserver = _OnAppLifecycleResumeObserver(() { _cleanUpDanglingCalls(); // unawaited