编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

html5+ & mui框架facebook登录插件(ios版)

wxchong 2024-08-06 03:12:00 开源技术 16 ℃ 0 评论

下面贴出关键代码,稍后完善更多细节步骤。个人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文件

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表