下面贴出关键代码,稍后完善更多细节步骤。个人ios开发经验不多,如果有更好的集成方式,请大家分享!
前提:
1. 能在Xcode中成功运行官方给出的离线打包演示应用 HBuilder-Hello (iOS平台5+SDK集成)
2. 注册了facebook开发者平台,并完成了官方ios集成步骤,参考:[](https://developers.facebook.com/docs/facebook-login/ios?sdk=fbsdk&locale=zh_CN)
源代码目录结构
1. js层代码调用插件login.js
loginWithFacebook: function() { Common.showLoading(); setTimeout(function(){ if(App.timeout) { Common.hideLoading(); mui.toast(Common.messages.LOGIN_TIMEOUT,{ duration:'short', type:'div' }); } }, 30000); if(Common.debug) { setTimeout(function(){ App.facebookAuthSuccessCallBack('{"picture":{"data":{"height":50,"is_silhouette":false,"url":"https:\/\/platform-lookaside.fbsbx.com\/platform\/profilepic\/?asid=1799672767573170&height=50&width=50&ext=1529946538&hash=AeT-c8Gg8kljhvAC","width":50}},"name":"Nick Name","id":"1791872767573170","email":"last.first@gmail.com","permissions":{"data":[{"permission":"user_birthday","status":"granted"},{"permission":"user_hometown","status":"granted"},{"permission":"user_location","status":"granted"},{"permission":"user_posts","status":"granted"},{"permission":"user_gender","status":"granted"},{"permission":"user_link","status":"granted"},{"permission":"user_age_range","status":"granted"},{"permission":"email","status":"granted"},{"permission":"public_profile","status":"granted"}]},"age_range":{"min":21},"link":"https:\/\/www.facebook.com\/app_scoped_user_id\/YXNpZADpBWEZAmSmJjc01BLXJNTGt4UDd0RlZAicXpYVG5HbTV3YUl2T29uNNNNMWpGWndhVEVieTI4S18zcDVuUjczUHRmUHgwYm8xUkwtU1lHWENuRW9vUnE2clFtalVLaWs4SldxT05iWUxZAUlZA2bjRHemhE\/","gender":"male","birthday":"01\/01\/1990","location":{"id":"106324044973002","name":"Shanghai, China"}}'); //App.facebookAuthCancelCallBack(); //App.facebookAuthErrorCallBack("auth fail!"); }, 2000); }else { //plus.facebookplug.logOut(); plus.facebookplug.logIn(App.facebookAuthSuccessCallBack, App.facebookAuthErrorCallBack); } }, // 这个回调函数会在 cn.shaketowin.app.SDK_WebApp.java 原生类中调用, 参考类中的excuteJSCode()方法 facebookAuthSuccessCallBack: function(data) { App.timeout = false; if(data != null) { //alert("===facebookAuthSuccessCallBack(), data: " + JSON.stringify(data)); // data example: {"picture":{"data":{"height":50,"is_silhouette":false,"url":"https:\/\/platform-lookaside.fbsbx.com\/platform\/profilepic\/?asid=1791872767573170&height=50&width=50&ext=1529946538&hash=AeT-c8Gg8kljhvAC","width":50}},"name":"Nick Name","id":"1987872767573170","email":"last.first@gmail.com","permissions":{"data":[{"permission":"user_birthday","status":"granted"},{"permission":"user_hometown","status":"granted"},{"permission":"user_location","status":"granted"},{"permission":"user_posts","status":"granted"},{"permission":"user_gender","status":"granted"},{"permission":"user_link","status":"granted"},{"permission":"user_age_range","status":"granted"},{"permission":"email","status":"granted"},{"permission":"public_profile","status":"granted"}]},"age_range":{"min":21},"link":"https:\/\/www.facebook.com\/app_scoped_user_id\/YXNpZADpBWEZAmSmJjc01BLXJNTGt4UD09RlZAicXpYVG5HbTV3YUl2T29uVTNNMWpGWndhVEVieTI4S18zcDVuUjczUHRmUHgwYm8xUkwtU1lHWENuRW9vUnE2clFtalVLaWs4SldxT05iWUxZAUlZA2bjRHemhE\/","gender":"male","birthday":"01\/01\/1990","location":{"id":"116324086073002","name":"Shanghai, China"}} try{ var facebookUser = JSON.parse(data); facebookUser.unionid = facebookUser.id; mui.toast(Common.messages.LOGIN_SUCCESS,{ duration:'short', type:'div' }); App.checkUserIsExist(facebookUser, "facebook"); }catch(err) { Common.hideLoading(); mui.toast(Common.messages.LOGIN_FAIL,{ duration:'long', type:'div' }); Common.log("====login.js, facebookAuthSuccessCallBack(), decode facebook user JSON string fail!"); } }else { Common.hideLoading(); App.facebookAuthErrorCallBack(); } }, // 这个回调函数会在 cn.shaketowin.app.SDK_WebApp.java 原生类中调用, 参考类中的excuteJSCode()方法 facebookAuthCancelCallBack: function() { App.timeout = false; Common.hideLoading(); mui.toast(Common.messages.LOGIN_CANCEL,{ duration:'long', type:'div' }); }, // 这个回调函数会在 cn.shaketowin.app.SDK_WebApp.java 原生类中调用, 参考类中的excuteJSCode()方法 facebookAuthErrorCallBack: function(error) { App.timeout = false; Common.hideLoading(); mui.toast(Common.messages.LOGIN_FAIL,{ duration:'long', type:'div' }); },
2. js层代码插件facebookplug.js
document.addEventListener( "plusready", function() { var facebookplug = { logIn : function (successCallback, errorCallback ) { var success = typeof successCallback !== 'function' ? null : function(args) { successCallback(args); }, fail = typeof errorCallback !== 'function' ? null : function(code) { errorCallback(code); }; callbackID = window.plus.bridge.callbackId(success, fail); return window.plus.bridge.exec('facebookloginplugin', "LogIn", [callbackID]); }, logOut : function () { window.plus.bridge.exec('facebookloginplugin', "LogOut", []); }, }; window.plus.facebookplug = facebookplug; }, true );
3. 原生层FacebookLoginPlugin.h
// // FacebookLoginPlugin.h // // #include "PGPlugin.h" #include "PGMethod.h" #import <Foundation/Foundation.h> @interface FacebookLoginPlugin : PGPlugin - (void)LogIn:(PGMethod*)command; - (void)LogOut:(PGMethod*)command; @end
4. 原生层FacebookLoginPlugin.m
// // FacebookLoginPlugin.m // #import "FacebookLoginPlugin.h" #import "PDRCoreAppFrame.h" #import "H5WEEngineExport.h" #import "PDRToolSystemEx.h" // 扩展插件中需要引入需要的系统库 #import <LocalAuthentication/LocalAuthentication.h> #import <FBSDKCoreKit/FBSDKCoreKit.h> #import <FBSDKLoginKit/FBSDKLoginKit.h> @implementation FacebookLoginPlugin #pragma mark 这个方法在使用WebApp方式集成时触发,WebView集成方式不触发 /* * WebApp启动时触发 * 需要在PandoraApi.bundle/feature.plist/注册插件里添加autostart值为true,global项的值设置为true */ - (void) onAppStarted:(NSDictionary*)options{ NSLog(@"5+ WebApp启动时触发"); // 可以在这个方法里向Core注册扩展插件的JS } // 监听基座事件事件 // 应用退出时触发 - (void) onAppTerminate{ // NSLog(@"APPDelegate applicationWillTerminate 事件触发时触发"); } // 应用进入后台时触发 - (void) onAppEnterBackground{ // NSLog(@"APPDelegate applicationDidEnterBackground 事件触发时触发"); } // 应用进入前天时触发 - (void) onAppEnterForeground{ // NSLog(@"APPDelegate applicationWillEnterForeground 事件触发时触发"); } #pragma mark 以下为插件方法,由JS触发, WebView集成和WebApp集成都可以触发 // 登录 - (void)LogIn:(PGMethod*)commands { if ( commands ) { // CallBackid 异步方法的回调id,H5+ 会根据回调ID通知JS层运行结果成功或者失败 NSString* cbId = [commands.arguments objectAtIndex:0]; if ([FBSDKAccessToken currentAccessToken]) { //NSLog(@"==========LogIn(), already have token"); [self GetUserInfo:cbId]; }else{ /* * Facebook会对i应用访问的字段进行控制(https://developers.facebook.com/apps/193845774573048/review-status/) * 应用审核说明:https://developers.facebook.com/docs/apps/review/#app-review * 默认不需要审核的有:@"public_profile", @"email" * 如下权限系统提交应用审核才可以访问: @"public_profile", @"email", @"user_age_range", @"user_birthday", @"user_gender", @"user_hometown", @"user_link", @"user_location" * 如果需要访问相对应的字段,将字段放入的代码 [login logInWithReadPermissions:@[@"public_profile", @"email"] 参数即可 */ FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init]; login.loginBehavior = FBSDKLoginBehaviorWeb; [login logInWithReadPermissions:@[@"public_profile", @"email"] handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) { if (error) { [self CallWebAppJSFun: cbId status: @"ERROR" message: error.localizedDescription]; } else if (result.isCancelled) { [self CallWebAppJSFun: cbId status: @"ERROR" message: @"cancel"]; } else { // If you ask for multiple permissions at once, you // should check if specific permissions missing //NSLog(@"========Permission 2: %@",result.grantedPermissions); [self GetUserInfo:cbId]; } }]; } } } // 退出登录 - (void)LogOut:(PGMethod *)command { FBSDKLoginManager *loginManager = [[FBSDKLoginManager alloc] init]; [loginManager logOut]; // or //[FBSDKAccessToken setCurrentAccessToken:nil]; } // 获取用户信息 - (void)GetUserInfo:(NSString *) cbId { /* * Facebook会对i应用访问的字段进行控制(https://developers.facebook.com/apps/193845774573048/review-status/) * 应用审核说明:https://developers.facebook.com/docs/apps/review/#app-review * 对应默认不需要审核的字段@"public_profile", @"email"的是@"id,name,first_name,last_name,email,picture.type(large)“ * 对应提交应用审核才可以访问字段有 @"cover,picture.type(large),id,name,first_name,last_name,gender,birthday,email,location,hometown,about,photos,age_range,link" * 如果需要访问相对应的字段,将字段放入的代码 parameters:[NSDictionary dictionaryWithObject:@"cover,..." forKey:@"fields"] 参数即可 */ [[[FBSDKGraphRequest alloc] initWithGraphPath:@"me" parameters:[NSDictionary dictionaryWithObject:@"id,name,first_name,last_name,email,picture" forKey:@"fields"]] startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) { if (!error) { //NSLog(@"==========GetUserInfo(), username: %@", [result valueForKey:@"name"]); // NSString *userID = [[FBSDKAccessToken currentAccessToken] userID]; // NSString *userName = [result valueForKey:@"name"]; // NSString *email = [result valueForKey:@"email"]; // NSString *userImageURL = [NSString stringWithFormat:@"https://graph.facebook.com/%@/picture?type=large", [[FBSDKAccessToken currentAccessToken] userID]]; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:result options:NSJSONWritingPrettyPrinted error:nil]; NSString *userInfo = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; //NSLog(@"==========GetUserInfo(), userInfo: %@", userInfo); [self CallWebAppJSFun: cbId status: @"OK" message: userInfo]; } else{ [self CallWebAppJSFun: cbId status: @"ERROR" message: error.localizedDescription]; } }]; } // 回调通知JS层 - (void)CallWebAppJSFun:(NSString *) cbId status:(NSString *) st message:(NSString *) msg { // 运行Native代码结果和预期相同,调用回调通知JS层运行成功并返回结果 // PDRCommandStatusOK 表示触发JS层成功回调方法 // PDRCommandStatusError 表示触发JS层错误回调方法 // 如果方法需要持续触发页面回调,可以通过修改 PDRPluginResult 对象的keepCallback 属性值来表示当前是否可重复回调, true 表示可以重复回调 false 表示不可重复回调 默认值为false PDRPluginResult * pResult = nil; if([st isEqualToString: @"OK"]) { pResult = [PDRPluginResult resultWithStatus:PDRCommandStatusOK messageAsString: msg]; }else { // 如果Native代码运行结果和预期不同,需要通过回调通知JS层出现错误,并返回错误提示 pResult = [PDRPluginResult resultWithStatus:PDRCommandStatusError messageAsString:msg]; } // 通知JS层Native层运行结果 [self toCallback:cbId withReslut:[pResult toJSONString]]; } // 调用指纹解锁 - (void)AuthenticateUser:(PGMethod*)command { if (nil == command) { return; } BOOL isSupport = false; NSString* pcbid = [command.arguments objectAtIndex:0]; NSError* error = nil; NSString* LocalReason = @"HBuilder指纹验证"; // Touch ID 是IOS 8 以后支持的功能 if ([PTDeviceOSInfo systemVersion] >= PTSystemVersion8Series) { LAContext* context = [[LAContext alloc] init]; if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) { isSupport = true; [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:LocalReason reply:^(BOOL success, NSError * _Nullable error) { PDRPluginResult * pResult = nil; if (success) { pResult = [PDRPluginResult resultWithStatus: PDRCommandStatusOK messageAsDictionary:@{@"state":@(0), @"message":@"成功"}]; } else{ NSDictionary* pStringError = nil; switch (error.code) { case LAErrorSystemCancel: { pStringError = @{@"state":@(-1), @"message":@"系统取消授权(例如其他APP切入)"}; break; } case LAErrorUserCancel: { pStringError = @{@"state":@(-2), @"message":@"用户取消Touch ID授权"}; break; } case LAErrorUserFallback: { pStringError = @{@"state":@(-3), @"message":@"用户选择输入密码"}; break; } case LAErrorTouchIDNotAvailable:{ pStringError = @{@"state":@(-4), @"message":@"设备Touch ID不可用"}; break; } case LAErrorTouchIDLockout:{ pStringError = @{@"state":@(-5), @"message":@"Touch ID被锁"}; break; } case LAErrorAppCancel:{ pStringError = @{@"state":@(-6), @"message":@"软件被挂起取消授权"}; break; } default: { pStringError = @{@"state":@(-7), @"message":@"其他错误"}; break; } } pResult = [PDRPluginResult resultWithStatus:PDRCommandStatusError messageAsDictionary:pStringError]; } [self toCallback:pcbid withReslut:[pResult toJSONString]]; }]; } else{ NSDictionary* pStringError = nil; switch (error.code) { case LAErrorTouchIDNotEnrolled: { pStringError = @{@"state":@(-11), @"message":@"设备Touch ID不可用"}; break; } case LAErrorPasscodeNotSet: { pStringError = @{@"state":@(-12), @"message":@"用户未录入Touch ID"}; break; } default: break; } } } if (!isSupport) { PDRPluginResult* pResult = [PDRPluginResult resultWithStatus:PDRCommandStatusError messageAsString:@"Device Not Support"]; [self toCallback:pcbid withReslut:[pResult toJSONString]]; } } @end
5. 原生层AppDelegate.m(在原有函数上新增一行FB的代码,这里仅贴出需要修改的函数的代码)
// // AppDelegate.m // #import "AppDelegate.h" #import "PDRCore.h" #import "PDRCommonString.h" #import "ViewController.h" #import "PDRCoreApp.h" #import "DCADManager.h" #import "PDRCoreAppManager.h" #import <FBSDKCoreKit/FBSDKCoreKit.h> // 示例默认带开屏广告,如果不需要广告,可注释下面一行 #define dcSplashAd @interface AppDelegate () <DCADManagerDelgate, PDRCoreDelegate> @property (strong, nonatomic) ViewController *h5ViewContoller; @end @implementation AppDelegate @synthesize window = _window; #pragma mark - #pragma mark app lifecycle /* * @Summary:程序启动时收到push消息 */ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { BOOL ret = [PDRCore initEngineWihtOptions:launchOptions withRunMode:PDRCoreRunModeNormal withDelegate:self]; DCADManager *adManager = [DCADManager adManager]; UIViewController* adViewController = [adManager getADViewController]; adManager.delegate = self; UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; self.window = window; ViewController *viewController = [[ViewController alloc] init]; self.h5ViewContoller = viewController; UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController]; self.rootViewController = navigationController; navigationController.navigationBarHidden = YES; if ( adViewController ) { [navigationController pushViewController:adViewController animated:NO]; } else { [self startMainApp]; self.h5ViewContoller.showLoadingView = YES; } self.window.rootViewController = navigationController; [self.window makeKeyAndVisible]; [[FBSDKApplicationDelegate sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions]; return ret; } #pragma mark - #pragma mark URL - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options{ //NSLog(@"==========here(), url: %@", url); [self application:application handleOpenURL:url]; [[FBSDKApplicationDelegate sharedInstance] application:application openURL:url sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey] annotation:options[UIApplicationOpenURLOptionsAnnotationKey] ]; return YES; }
6. Supporting Files/Info.plist文件
本文暂时没有评论,来添加一个吧(●'◡'●)