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

貼出源碼回報社區!javascript

下面貼出關鍵代碼,稍後完善更多細節步驟。我的ios開發經驗很少,若是有更好的集成方式,請你們分享!java

前提:
1. 能在Xcode中成功運行官方給出的離線打包演示應用 HBuilder-Hello (iOS平臺5+SDK集成)
2. 註冊了facebook開發者平臺,並完成了官方ios集成步驟,參考:[](https://developers.facebook.com/docs/facebook-login/ios?sdk=fbsdk&locale=zh_CN)ios

源代碼目錄結構
json

 

1. js層代碼調用插件login.jsapp

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.hide

//
//  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的代碼,這裏僅貼出須要修改的函數的代碼)post

//
//  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文件ui

相關文章
相關標籤/搜索