HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

facebook登录插件(ios版)

facebook

贴出源码回报社区!

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

继续阅读 »

贴出源码回报社区!

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

收起阅读 »

uni-app 中使用微信小程序第三方 SDK 及资源汇总

高德地图 SDK 小程序

本文以高德微信小程序 SDK 为例,简述如何在 uni-app 中利用微信小程序第三方 SDK,实现 App 端和微信小程序的代码通用。

获取SDK

首先在高德开放平台,注册账号并且申请相关的 key 等信息;
然后下载它的微信小程序版 SDK:微信小程序 SDK
然后填写app包名,申请原生sdk的appkey信息,但不需要下载原生sdk。注意:App侧在Android中使用定位,或者Android、iOS使用地图,仍然需要同时向高德申请原生sdk的key信息,填写在manifest的app sdk配置中。

新建一个 uni-app 项目,新建一个 common 目录,然后将前面下载得到的 amap-wx.js 的文件复制进去。

Tip:这个 common 目录只是举例,并非强制约定。但是,不要放在 static 目录下。

引入SDK

新建的 uni-app 默认会有一个 index 页,在 index.vue 中,引入高德小程序 SDK。

import amap from '../../common/amap-wx.js';  
export default {  
}

在 onLoad 中初始化一个高德小程序 SDK 的实例对象。

import amap from '../../common/amap-wx.js';  
export default {  
    data() {  
        return {  
            amapPlugin: null,  
            key: '这里填写高德开放平台上申请的key'  
        }  
    },  
    onLoad() {  
        this.amapPlugin = new amap.AMapWX({  
            key: this.key  
        });  
    }  
}

使用API

利用高德小程序 SDK,获取当前位置地址信息,以及当前位置的天气情况。

import amap from '../../common/amap-wx.js';  
export default {  
    data() {  
        return {  
            amapPlugin: null,  
            key: '高德key',  
            addressName: '',  
            weather: {  
                hasData: false,  
                data: []  
            }  
        }  
    },  
    onLoad() {  
        this.amapPlugin = new amap.AMapWX({  
            key: this.key  
        });  
    },  
    methods: {  
        getRegeo() {  
            uni.showLoading({  
                title: '获取信息中'  
            });  
            this.amapPlugin.getRegeo({  
                success: (data) => {  
                    console.log(data)  
                    this.addressName = data[0].name;  
                    uni.hideLoading();  
                }  
            });  
        }  
    }  
}

其它 SDK

高德小程序 SDK 类似辅助工具库,使用时在需要的页面中引入即可。

还有一种 SDK 比如阿拉丁、诸葛IO等统计类的 SDK 需要全局引入。小程序是在 app.js 中 引入。在 uni-app 中,则是在 main.js 中引入。

示例

附件中有完整的示例,下载后解压拖进 HBuilderX,填写申请的高德 key 后即可运行体验。

如果大家在使用微信小程序的第三方 SDK 时遇到问题,请在社区单独发帖描述清楚问题,并一定附上项目源码,方便我们测试,感谢配合。

更多 SDK 资源

通用 SDK

App 端和微信小程序均可使用小程序版 SDK

微信小程序

仅适用于微信小程序

这些 SDK 因为当前 uni-app 还未统一app和小程序的直播api而暂时只能在小程序中使用。

补充完善

以上列出来的只是一部分资源信息,还有一些其它的 SDK 可能没有涉及到,欢迎大家继续补充相关信息。

再次强调,因为uni-app的app端其实是一个强化版的小程序引擎,所以支持小程序sdk在app端使用。但这些sdk在h5端、支付宝百度等小程序平台无法使用。

继续阅读 »

本文以高德微信小程序 SDK 为例,简述如何在 uni-app 中利用微信小程序第三方 SDK,实现 App 端和微信小程序的代码通用。

获取SDK

首先在高德开放平台,注册账号并且申请相关的 key 等信息;
然后下载它的微信小程序版 SDK:微信小程序 SDK
然后填写app包名,申请原生sdk的appkey信息,但不需要下载原生sdk。注意:App侧在Android中使用定位,或者Android、iOS使用地图,仍然需要同时向高德申请原生sdk的key信息,填写在manifest的app sdk配置中。

新建一个 uni-app 项目,新建一个 common 目录,然后将前面下载得到的 amap-wx.js 的文件复制进去。

Tip:这个 common 目录只是举例,并非强制约定。但是,不要放在 static 目录下。

引入SDK

新建的 uni-app 默认会有一个 index 页,在 index.vue 中,引入高德小程序 SDK。

import amap from '../../common/amap-wx.js';  
export default {  
}

在 onLoad 中初始化一个高德小程序 SDK 的实例对象。

import amap from '../../common/amap-wx.js';  
export default {  
    data() {  
        return {  
            amapPlugin: null,  
            key: '这里填写高德开放平台上申请的key'  
        }  
    },  
    onLoad() {  
        this.amapPlugin = new amap.AMapWX({  
            key: this.key  
        });  
    }  
}

使用API

利用高德小程序 SDK,获取当前位置地址信息,以及当前位置的天气情况。

import amap from '../../common/amap-wx.js';  
export default {  
    data() {  
        return {  
            amapPlugin: null,  
            key: '高德key',  
            addressName: '',  
            weather: {  
                hasData: false,  
                data: []  
            }  
        }  
    },  
    onLoad() {  
        this.amapPlugin = new amap.AMapWX({  
            key: this.key  
        });  
    },  
    methods: {  
        getRegeo() {  
            uni.showLoading({  
                title: '获取信息中'  
            });  
            this.amapPlugin.getRegeo({  
                success: (data) => {  
                    console.log(data)  
                    this.addressName = data[0].name;  
                    uni.hideLoading();  
                }  
            });  
        }  
    }  
}

其它 SDK

高德小程序 SDK 类似辅助工具库,使用时在需要的页面中引入即可。

还有一种 SDK 比如阿拉丁、诸葛IO等统计类的 SDK 需要全局引入。小程序是在 app.js 中 引入。在 uni-app 中,则是在 main.js 中引入。

示例

附件中有完整的示例,下载后解压拖进 HBuilderX,填写申请的高德 key 后即可运行体验。

如果大家在使用微信小程序的第三方 SDK 时遇到问题,请在社区单独发帖描述清楚问题,并一定附上项目源码,方便我们测试,感谢配合。

更多 SDK 资源

通用 SDK

App 端和微信小程序均可使用小程序版 SDK

微信小程序

仅适用于微信小程序

这些 SDK 因为当前 uni-app 还未统一app和小程序的直播api而暂时只能在小程序中使用。

补充完善

以上列出来的只是一部分资源信息,还有一些其它的 SDK 可能没有涉及到,欢迎大家继续补充相关信息。

再次强调,因为uni-app的app端其实是一个强化版的小程序引擎,所以支持小程序sdk在app端使用。但这些sdk在h5端、支付宝百度等小程序平台无法使用。

收起阅读 »

uniapp个人作品展示和经验分享

总的来说,体验不错,值得入坑,希望 web view这个在多些功能,比如获取当前url,h5+监听太麻烦了,而且卡顿

继续阅读 »

总的来说,体验不错,值得入坑,希望 web view这个在多些功能,比如获取当前url,h5+监听太麻烦了,而且卡顿

收起阅读 »

如何用PHP读取Excel文件数据及内容信息

  在文章开始介绍前,大家需要了解一下PHPExcel是什么?PHPExcel 就是一个用来操作Office Excel 文档的PHP类库。接下来讲解如何利用PHPExcel类库将Excel表格内的信息内容读取出来,完整代码如下:

<?php

$fileName = "1.xls";

if (!file_exists($fileName)) {

return "文件不存在!";

}

// 引入PHPExcel

require_once "./PHPExcel/IOFactory.php";

// 载入当前文件

$phpExcel = PHPExcel_IOFactory::load($fileName);

// 设置为默认表

$phpExcel->setActiveSheetIndex(0);

// 获取表格数量

$sheetCount = $phpExcel->getSheetCount();

// 获取行数

$row = $phpExcel->getActiveSheet()->getHighestRow();

// 获取列数

$column = $phpExcel->getActiveSheet()->getHighestColumn();

echo "表格数目为:$sheetCount" . "表格的行数:$row" . "列数:$column";

$data = [];

// 行数循环

for ($i = 1; $i <= $row; $i++) {

// 列数循环

for ($c = 'A'; $c <= $column; $c++) {

$data[] = $phpExcel->getActiveSheet()->getCell($c . $i)->getValue();

}

echo "

";

print_r($data);

}

  在上述代码中,先if判断Excel表格是否存在,再用require_once引入PHPExcel类库中IOFactory.php这个类,然后使用PHPExcel类库的一个方法载入Excel文件,这里将载入的Excel文件赋值于$phpExcel变量。

  然后再将$phpExcel变量通过分别指定相应的方法来获取Excel表格的数目、行数、列数以及通过setActiveSheetIndex(0)方法设置这个表格为默认(0表示默认)。

  此时输出表格的数目、行数、列数的结果,通过浏览器访问的结果就出来了。然后我们用for循环遍历出表格的所有内容,再定义一个数组$data来接收这些内容。

  本文由专业的郑州app开发公司燚轩科技整理发布,原创不易,如需转载请注明出处。

继续阅读 »

  在文章开始介绍前,大家需要了解一下PHPExcel是什么?PHPExcel 就是一个用来操作Office Excel 文档的PHP类库。接下来讲解如何利用PHPExcel类库将Excel表格内的信息内容读取出来,完整代码如下:

<?php

$fileName = "1.xls";

if (!file_exists($fileName)) {

return "文件不存在!";

}

// 引入PHPExcel

require_once "./PHPExcel/IOFactory.php";

// 载入当前文件

$phpExcel = PHPExcel_IOFactory::load($fileName);

// 设置为默认表

$phpExcel->setActiveSheetIndex(0);

// 获取表格数量

$sheetCount = $phpExcel->getSheetCount();

// 获取行数

$row = $phpExcel->getActiveSheet()->getHighestRow();

// 获取列数

$column = $phpExcel->getActiveSheet()->getHighestColumn();

echo "表格数目为:$sheetCount" . "表格的行数:$row" . "列数:$column";

$data = [];

// 行数循环

for ($i = 1; $i <= $row; $i++) {

// 列数循环

for ($c = 'A'; $c <= $column; $c++) {

$data[] = $phpExcel->getActiveSheet()->getCell($c . $i)->getValue();

}

echo "

";

print_r($data);

}

  在上述代码中,先if判断Excel表格是否存在,再用require_once引入PHPExcel类库中IOFactory.php这个类,然后使用PHPExcel类库的一个方法载入Excel文件,这里将载入的Excel文件赋值于$phpExcel变量。

  然后再将$phpExcel变量通过分别指定相应的方法来获取Excel表格的数目、行数、列数以及通过setActiveSheetIndex(0)方法设置这个表格为默认(0表示默认)。

  此时输出表格的数目、行数、列数的结果,通过浏览器访问的结果就出来了。然后我们用for循环遍历出表格的所有内容,再定义一个数组$data来接收这些内容。

  本文由专业的郑州app开发公司燚轩科技整理发布,原创不易,如需转载请注明出处。

收起阅读 »

uniapp: request竟然没有timeout, 这是基本功能吧 ,既然没有 只好自己写个了, 希望官方提供个

uniapp

更新: 官网找到timeout了 藏的太深 没有和request介绍联系起来 放个链接地址:networktimeout
http://uniapp.dcloud.io/collocation/manifest?id=networktimeout

封装

let globalPostRequest = function (url,data,callback,isWait=true,isPost=true) {  
    if (isWait) {  
        uni.showLoading({  
            title: '正在加载'  
        });  
    }  
    console.log('正在请求:xxxxxxxxx' + url);  
    console.log('参数:' + JSON.stringify(data));  
    let requestName = 'requestTask'+ JSON.stringify(url);  
    let timeout = null;  
    requestName = uni.request({  
        url: 'xxxxxxxxx' + url,  
        data: data,  
        method: isPost == true?'POST':'GET',  
        dataType: 'json',  
        header: {  
            'Accept-Language':'zh-CN,en-US;q=0.8'  
        },  
        success: (data,statusCode) => {  
            console.log('请求成功:'+JSON.stringify(data.data));  
            callback(data.data);  
        },  
        fail:() => {  
            console.log('请求失败fail');  
            const errordata = {"status":false,"code":404,"data":null,"message":"网络繁忙"}  
            callback(errordata);  
        },  
        complete:() => {  
            uni.hideLoading();  
            requestName = null;  
            if (timeout != null) {  
                clearTimeout(timeout);  
                timeout = null;  
            }  
        }  
    });  
    //timeout  
    timeout = setTimeout(() => {  
        if (requestName != null) {  
            requestName.abort();  
            console.log('请求失败abort');  
        }  
    },20000)  
}

调用

users_getMyBook:(userid) => {  
                qx.globalPostRequest('xxxxxxxxx',{  
                    userid:userid  
                },  
                function(data){  
                    if (data&&data.status) {  
                        //成功  
                    } else{  
                        uni.showToast({  
                            title: data.message,  
                            duration: 2000  
                        });  
                    }  
                })
继续阅读 »

更新: 官网找到timeout了 藏的太深 没有和request介绍联系起来 放个链接地址:networktimeout
http://uniapp.dcloud.io/collocation/manifest?id=networktimeout

封装

let globalPostRequest = function (url,data,callback,isWait=true,isPost=true) {  
    if (isWait) {  
        uni.showLoading({  
            title: '正在加载'  
        });  
    }  
    console.log('正在请求:xxxxxxxxx' + url);  
    console.log('参数:' + JSON.stringify(data));  
    let requestName = 'requestTask'+ JSON.stringify(url);  
    let timeout = null;  
    requestName = uni.request({  
        url: 'xxxxxxxxx' + url,  
        data: data,  
        method: isPost == true?'POST':'GET',  
        dataType: 'json',  
        header: {  
            'Accept-Language':'zh-CN,en-US;q=0.8'  
        },  
        success: (data,statusCode) => {  
            console.log('请求成功:'+JSON.stringify(data.data));  
            callback(data.data);  
        },  
        fail:() => {  
            console.log('请求失败fail');  
            const errordata = {"status":false,"code":404,"data":null,"message":"网络繁忙"}  
            callback(errordata);  
        },  
        complete:() => {  
            uni.hideLoading();  
            requestName = null;  
            if (timeout != null) {  
                clearTimeout(timeout);  
                timeout = null;  
            }  
        }  
    });  
    //timeout  
    timeout = setTimeout(() => {  
        if (requestName != null) {  
            requestName.abort();  
            console.log('请求失败abort');  
        }  
    },20000)  
}

调用

users_getMyBook:(userid) => {  
                qx.globalPostRequest('xxxxxxxxx',{  
                    userid:userid  
                },  
                function(data){  
                    if (data&&data.status) {  
                        //成功  
                    } else{  
                        uni.showToast({  
                            title: data.message,  
                            duration: 2000  
                        });  
                    }  
                })
收起阅读 »

html5 postMessage解决跨域、跨窗口消息传递

HTML5

  平时做web开发的时候关于消息传递,除了客户端与服务器传值还有几个经常会遇到以下这些问题,那么对此就来分析解答一下如何做吧:

  1.页面和其打开的新窗口的数据传递

  2.多窗口之间消息传递

  3.页面与嵌套的iframe消息传递

  4.上面三个问题的跨域数据传递

  postMessage()

  这些问题都有一些解决办法,但html5引入的message的API可以更方便、有效、安全的解决这些难题。postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。

  postMessage(data,origin)方法接受两个参数

  1.data:要传递的数据,html5规范中提到该参数可以是JavaScript的任意基本类型或可复制的对象,然而并不是所有浏览器都做到了这点儿,部分浏览器只能处理字符串参数,所以我们在传递参数的时候需要使用JSON.stringify()方法对对象参数序列化,在低版本IE中引用json2.js可以实现类似效果。

  2.origin:字符串参数,指明目标窗口的源,协议+主机+端口号[+URL],URL会被忽略,所以可以不写,这个参数是为了安全考虑,postMessage()方法只会将message传递给指定窗口,当然如果愿意也可以建参数设置为"*",这样可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。

源代码如下:

<div style="width:200px; float:left; margin-right:200px;border:solid 1px #333;">
<div id="color">Frame Color</div>
</div>
<div>
<iframe id="child" src="http://lsLib.com/lsLib.html"></iframe>
</div>
我们可以在http://test.com/index.html通过postMessage()方法向跨域的iframe页面http://lsLib.com/lsLib.html传递消息
window.onload=function(){
window.frames[0].postMessage('getcolor','http://lslib.com');
}
接收消息
test.com上面的页面向lslib.com发送了消息,那么在lslib.com页面上如何接收消息呢,监听window的message事件就可以
window.addEventListener('message',function(e){
if(e.source!=window.parent) return;
var color=container.style.backgroundColor;
window.parent.postMessage(color,'');
},false);
这样我们就可以接收任何窗口传递来的消息了,为了安全起见,我们利用这时候的MessageEvent对象判断了一下消息源,MessageEvent是一个这样的东东有几个重要属性:
data:顾名思义,是传递来的message
source:发送消息的窗口对象
origin:发送消息窗口的源(协议+主机+端口号)
这样就可以接收跨域的消息了,我们还可以发送消息回去,方法类似
简单的demo,在这个例子中,左边的div会根据右边iframe内div颜色变化而变化
在例子中页面加载的时候主页面向iframe发送’getColor‘ 请求(参数没实际用处)
window.onload=function(){
window.frames[0].postMessage('getcolor','http://lslib.com');
}
iframe接收消息,并把当前颜色发送给主页面呢
window.addEventListener('message',function(e){
if(e.source!=window.parent) return;
var color=container.style.backgroundColor;
window.parent.postMessage(color,'
');
},false);
主页面接收消息,更改自己div颜色
window.addEventListener('message',function(e){
var color=e.data;
document.getElementById('color').style.backgroundColor=color;
},false);
当点击iframe事触发其变色方法,把最新颜色发送给主页面
function changeColor () {
var color=container.style.backgroundColor;
if(color=='rgb(204, 102, 0)'){
color='rgb(204, 204, 0)';
}else{
color='rgb(204,102,0)';
}
container.style.backgroundColor=color;
window.parent.postMessage(color,'*');
}
主页面还是利用刚才监听message事件的程序处理自身变色
window.addEventListener('message',function(e){
var color=e.data;
document.getElementById('color').style.backgroundColor=color;
},false);

  最后很简单的用法却解决了大问题,据说Facebook已经在使用了,而且这也是html5另一个API——web workers传递消息的方法,那么它的浏览器兼容性怎么样呢?所谓浏览器兼容性几乎变成了IE几开始支持的问题了。。。不过好消息是跟localStorage一样,IE8+都支持了,只不过有些浏览器的低版本(比如FireFox4.0)并不支持window.onmessage=function(){}这种写法,所以建议最好使用事件绑定的写法,为了兼容IE,也要判断是否支持addEventListener。

继续阅读 »

  平时做web开发的时候关于消息传递,除了客户端与服务器传值还有几个经常会遇到以下这些问题,那么对此就来分析解答一下如何做吧:

  1.页面和其打开的新窗口的数据传递

  2.多窗口之间消息传递

  3.页面与嵌套的iframe消息传递

  4.上面三个问题的跨域数据传递

  postMessage()

  这些问题都有一些解决办法,但html5引入的message的API可以更方便、有效、安全的解决这些难题。postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。

  postMessage(data,origin)方法接受两个参数

  1.data:要传递的数据,html5规范中提到该参数可以是JavaScript的任意基本类型或可复制的对象,然而并不是所有浏览器都做到了这点儿,部分浏览器只能处理字符串参数,所以我们在传递参数的时候需要使用JSON.stringify()方法对对象参数序列化,在低版本IE中引用json2.js可以实现类似效果。

  2.origin:字符串参数,指明目标窗口的源,协议+主机+端口号[+URL],URL会被忽略,所以可以不写,这个参数是为了安全考虑,postMessage()方法只会将message传递给指定窗口,当然如果愿意也可以建参数设置为"*",这样可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。

源代码如下:

<div style="width:200px; float:left; margin-right:200px;border:solid 1px #333;">
<div id="color">Frame Color</div>
</div>
<div>
<iframe id="child" src="http://lsLib.com/lsLib.html"></iframe>
</div>
我们可以在http://test.com/index.html通过postMessage()方法向跨域的iframe页面http://lsLib.com/lsLib.html传递消息
window.onload=function(){
window.frames[0].postMessage('getcolor','http://lslib.com');
}
接收消息
test.com上面的页面向lslib.com发送了消息,那么在lslib.com页面上如何接收消息呢,监听window的message事件就可以
window.addEventListener('message',function(e){
if(e.source!=window.parent) return;
var color=container.style.backgroundColor;
window.parent.postMessage(color,'');
},false);
这样我们就可以接收任何窗口传递来的消息了,为了安全起见,我们利用这时候的MessageEvent对象判断了一下消息源,MessageEvent是一个这样的东东有几个重要属性:
data:顾名思义,是传递来的message
source:发送消息的窗口对象
origin:发送消息窗口的源(协议+主机+端口号)
这样就可以接收跨域的消息了,我们还可以发送消息回去,方法类似
简单的demo,在这个例子中,左边的div会根据右边iframe内div颜色变化而变化
在例子中页面加载的时候主页面向iframe发送’getColor‘ 请求(参数没实际用处)
window.onload=function(){
window.frames[0].postMessage('getcolor','http://lslib.com');
}
iframe接收消息,并把当前颜色发送给主页面呢
window.addEventListener('message',function(e){
if(e.source!=window.parent) return;
var color=container.style.backgroundColor;
window.parent.postMessage(color,'
');
},false);
主页面接收消息,更改自己div颜色
window.addEventListener('message',function(e){
var color=e.data;
document.getElementById('color').style.backgroundColor=color;
},false);
当点击iframe事触发其变色方法,把最新颜色发送给主页面
function changeColor () {
var color=container.style.backgroundColor;
if(color=='rgb(204, 102, 0)'){
color='rgb(204, 204, 0)';
}else{
color='rgb(204,102,0)';
}
container.style.backgroundColor=color;
window.parent.postMessage(color,'*');
}
主页面还是利用刚才监听message事件的程序处理自身变色
window.addEventListener('message',function(e){
var color=e.data;
document.getElementById('color').style.backgroundColor=color;
},false);

  最后很简单的用法却解决了大问题,据说Facebook已经在使用了,而且这也是html5另一个API——web workers传递消息的方法,那么它的浏览器兼容性怎么样呢?所谓浏览器兼容性几乎变成了IE几开始支持的问题了。。。不过好消息是跟localStorage一样,IE8+都支持了,只不过有些浏览器的低版本(比如FireFox4.0)并不支持window.onmessage=function(){}这种写法,所以建议最好使用事件绑定的写法,为了兼容IE,也要判断是否支持addEventListener。

收起阅读 »

【分享】环信IM SDK 移植分享

技术分享 uniapp

前言
环信IM小程序版本的SDK要正常在小程序里使用,开发者工具就必须开启ES6转ES5,而Uni-app 本身已经转过一次了,所以在转一次 strophe.js 就会报错,根本原因就是没有暴露接口了,所以,顺着这个思路,只要修改 strophe.js 这个js使其可以正常引入就行了。

使用方法

  1. 用我提供的 strophe.js 替换掉 环信官方小程序SDK里的 strophe.js
  2. 在需要聊天的页面引入WebIM.js文件
    let WebIM = require('../../common/sdk/WebIM')['default']  
    ...  
    onLoad:function(){  
    WebIM.conn.open({  
            user: '用户名',  
            pwd: '密码',  
            appKey: '环信官方申请的Key',  
            apiUrl: 'https://a1.easemob.com',  
        });  
        WebIM.conn.listen({  
            onOpened(message) {  
    // 如果没有开启自动登录,这里必须设置WebIM.conn.setPresence(); 否则无法接受消息  
                 WebIM.conn.setPresence();  
                console.log("onOpened", message);  
            },  
            onTextMessage: function (res) { //收到文本消息  
                console.log(res)  
            },  
        })  
    }
  3. 敬请享用吧

最后
如果帮到你请点个赞吧

继续阅读 »

前言
环信IM小程序版本的SDK要正常在小程序里使用,开发者工具就必须开启ES6转ES5,而Uni-app 本身已经转过一次了,所以在转一次 strophe.js 就会报错,根本原因就是没有暴露接口了,所以,顺着这个思路,只要修改 strophe.js 这个js使其可以正常引入就行了。

使用方法

  1. 用我提供的 strophe.js 替换掉 环信官方小程序SDK里的 strophe.js
  2. 在需要聊天的页面引入WebIM.js文件
    let WebIM = require('../../common/sdk/WebIM')['default']  
    ...  
    onLoad:function(){  
    WebIM.conn.open({  
            user: '用户名',  
            pwd: '密码',  
            appKey: '环信官方申请的Key',  
            apiUrl: 'https://a1.easemob.com',  
        });  
        WebIM.conn.listen({  
            onOpened(message) {  
    // 如果没有开启自动登录,这里必须设置WebIM.conn.setPresence(); 否则无法接受消息  
                 WebIM.conn.setPresence();  
                console.log("onOpened", message);  
            },  
            onTextMessage: function (res) { //收到文本消息  
                console.log(res)  
            },  
        })  
    }
  3. 敬请享用吧

最后
如果帮到你请点个赞吧

收起阅读 »

公众号模板消息功能的开发与设置

  对于公众号内模板消息功能的使用,首先去微信公众平台开通模板消息功能,认证的时间大约是3天。认证通过后选择模板,获得消息模板ID。此功能主要用于微信公众号消息提醒,比如客户的商家认证审核通过,用户购买商品成功等功能提醒,可以有效减少网站项目开发所必要的资金节约。下面重点来讲解一下接口代码:

接口代码如下:

// 字符编码

header("Content-Type:text/html; charset=utf-8");

// 微信接口类

class Wchat{

private static $appid;

private static $appsecret;

function __construct(){

self::$appid = '';

self::$appsecret ='';

}

// 微信授权地址

public static function getAuthorizeUrl($url){

$url_link = urlencode($url);

return "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" . self::$appid . "&redirect_uri={$url_link}&response_type=code&scope=snsapi_base&state=1#Wchat_redirect";

}

// 获取TOKEN

public static function getToken(){

$urla = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" . self::$appid . "&secret=" . self::$appsecret;

$outputa = self::curlGet($urla);

$result = json_decode($outputa, true);

return $result['access_token'];

}

/**

  • getUserInfo 获取用户信息

  • @param string $code 微信授权code

  • @param string $weiwei_token Token

  • @return array

*/

public static function getUserInfo($code, $weiwei_token){

$access_token_url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" . self::$appid . "&secret=" . self::$appsecret . "&code={$code}&grant_type=authorization_code";

$access_token_json = self::curlGet($access_token_url);

$access_token_array = json_decode($access_token_json, true);

$openid = $access_token_array['openid'];

$new_access_token = $weiwei_token;

//全局access token获得用户基本信息

$userinfo_url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token={$new_access_token}&openid={$openid}";

$userinfo_json = self::curlGet($userinfo_url);

$userinfo_array = json_decode($userinfo_json, true);

return $userinfo_array;

}

/**

  • pushMessage 发送自定义的模板消息

  • @param array $data 模板数据

$data = [

'openid' => '', 用户openid

'url' => '', 跳转链接

'template_id' => '', 模板id

'data' => [ // 消息模板数据

'first' => ['value' => urlencode('黄旭辉'),'color' => "#743A3A"],

'keyword1' => ['value' => urlencode('男'),'color'=>'blue'],

'keyword2' => ['value' => urlencode('1993-10-23'),'color' => 'blue'],

'remark' => ['value' => urlencode('我的模板'),'color' => '#743A3A']

]

];

  • @param string $topcolor 模板内容字体颜色,不填默认为黑色

  • @return array

*/

public static function pushMessage($data = [],$topcolor = '#0000'){

$template = [

'touser' => $data['openid'],

'template_id' => $data['template_id'],

'url' => $data['url'],

'topcolor' => $topcolor,

'data' => $data['data']

];

$json_template = json_encode($template);

$url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" . self::getToken();

$result = self::curlPost($url, urldecode($json_template));

$resultData = json_decode($result, true);

return $resultData;

}

/**

  • addLog 日志记录

  • @param string $log_content 日志内容

*/

public static function addLog($log_content = ''){

$data = "";

$data .= "DATE: [ " . date('Y-m-d H:i:s') . " ]\r\n";

$data .= "INFO: " . $log_content . "\r\n\r\n";

file_put_contents('/Wchat.log', $data, FILE_APPEND);

}

/**

  • 发送get请求

  • @param string $url 链接

  • @return bool|mixed

*/

private static function curlGet($url){

$curl = curl_init();

curl_setopt($curl, CURLOPT_URL, $url);

curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);

curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);

curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

$output = curl_exec($curl);

if(curl_errno($curl)){

return 'ERROR ' . curl_error($curl);

}

curl_close($curl);

return $output;

}

/**

  • 发送post请求

  • @param string $url 链接

  • @param string $data 数据

  • @return bool|mixed

*/

private static function curlPost($url, $data = null){

$curl = curl_init();

curl_setopt($curl, CURLOPT_URL, $url);

curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);

curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);

if(!empty($data)){

curl_setopt($curl, CURLOPT_POST, 1);

curl_setopt($curl, CURLOPT_POSTFIELDS, $data);

}

curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

$output = curl_exec($curl);

curl_close($curl);

return $output;

}

}

/**

  • get_page_url 获取完整URL

  • @return url

*/

function get_page_url($type = 0){

$pageURL = 'http';

if($_SERVER["HTTPS"] == 'on'){

$pageURL .= 's';

}

$pageURL .= '://';

if($type == 0){

$pageURL .= $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];

}else{

$pageURL .= $_SERVER["SERVER_NAME"];

}

return $pageURL;

}

// 获取用户openid

$Wchat = new Wchat();

if(empty($_GET['code']) || !isset($_GET['code'])){

// 通过授权获取code

$url = get_page_url();

$authorize_url = $Wchat->getAuthorizeUrl($url);

header("Location:{$authorize_url}"); // 重定向浏览器

exit();

}else{

// 获取微信用户信息

$uid=session("uid");

$info=M("user")->where("uid=$uid")->find();

$openid=$info['openid'];

$list=M("good")->where("uid=$uid and fabu=2")->select();

foreach ($list as $key => $value) {

$good_id[]=$value['id'];

}

$where['shop_uid']=$uid;

$where['good_id']=array("in",$good_id);

$where['price_state']=1;

$res=M("good_pai_price")->where($where)->order("addtime desc")->limit(1)->find();

$id=$res['good_id'];

$mai_uid=$res['uid'];

$goodinfo=M("good")->where("id=$id")->find();

// echo $mai_uid;exit;

$userinfo=M("user")->where("uid=$mai_uid")->find();

// var_dump($goodinfo);exit;

$code = $_GET['code'];

$weiwei_token = $Wchat->getToken(); // 获取微信token

$user_info = $Wchat->getUserInfo($code, $weiwei_token);

// $openid = $user_info['openid'];

公众号消息推送

$Wchat::pushMessage([

'openid' => $openid, // 用户openid

'access_token' => $weiwei_token,

'template_id' => "", // 填写你自己的消息模板ID

'data' => [ // 模板消息内容,根据模板详情进行设置

'first' => ['value' => urlencode("尊敬的".$info['nickname'].",您好,您的拍品已有人出价。"),'color' => "#743A3A"],

'keyword1' => ['value' => urlencode($goodinfo['desc']),'color'=>'blue'],

'keyword2' => ['value' => urlencode(date("Y-m-d H:i",$res['addtime'])),'color'=>'blue'],

'keyword3' => ['value' => urlencode($userinfo['name']),'color' => 'green'],

'keyword4' => ['value' => urlencode($userinfo['s_province']),'color' => 'green'],

'keyword5' => ['value' => urlencode($res['price']/100),'color' => 'green'],

'remark' => ['value' => urlencode("更多出价详情,请点击页面进行实时查询。"),'color' => '#743A3A']

],

'url' => 'http://www.xxxx.com/Shop/info?id='.$id // 消息跳转链接

]);

}

  1. php调用接口代码

Php代码如下:

public function msg(){

require_once 'WchatAction.class.php';

// 微信接口类

$wchat = new \Wchat();

$wchat->pushMessage();

}

  好了,以上就是全部的源码了,如果大家还是存在不理解的地方,可以留言咨询。

  本文由专业的郑州小程序开发公司燚轩科技整理发布,原创不易,如需转载请注明出处!

继续阅读 »

  对于公众号内模板消息功能的使用,首先去微信公众平台开通模板消息功能,认证的时间大约是3天。认证通过后选择模板,获得消息模板ID。此功能主要用于微信公众号消息提醒,比如客户的商家认证审核通过,用户购买商品成功等功能提醒,可以有效减少网站项目开发所必要的资金节约。下面重点来讲解一下接口代码:

接口代码如下:

// 字符编码

header("Content-Type:text/html; charset=utf-8");

// 微信接口类

class Wchat{

private static $appid;

private static $appsecret;

function __construct(){

self::$appid = '';

self::$appsecret ='';

}

// 微信授权地址

public static function getAuthorizeUrl($url){

$url_link = urlencode($url);

return "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" . self::$appid . "&redirect_uri={$url_link}&response_type=code&scope=snsapi_base&state=1#Wchat_redirect";

}

// 获取TOKEN

public static function getToken(){

$urla = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" . self::$appid . "&secret=" . self::$appsecret;

$outputa = self::curlGet($urla);

$result = json_decode($outputa, true);

return $result['access_token'];

}

/**

  • getUserInfo 获取用户信息

  • @param string $code 微信授权code

  • @param string $weiwei_token Token

  • @return array

*/

public static function getUserInfo($code, $weiwei_token){

$access_token_url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" . self::$appid . "&secret=" . self::$appsecret . "&code={$code}&grant_type=authorization_code";

$access_token_json = self::curlGet($access_token_url);

$access_token_array = json_decode($access_token_json, true);

$openid = $access_token_array['openid'];

$new_access_token = $weiwei_token;

//全局access token获得用户基本信息

$userinfo_url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token={$new_access_token}&openid={$openid}";

$userinfo_json = self::curlGet($userinfo_url);

$userinfo_array = json_decode($userinfo_json, true);

return $userinfo_array;

}

/**

  • pushMessage 发送自定义的模板消息

  • @param array $data 模板数据

$data = [

'openid' => '', 用户openid

'url' => '', 跳转链接

'template_id' => '', 模板id

'data' => [ // 消息模板数据

'first' => ['value' => urlencode('黄旭辉'),'color' => "#743A3A"],

'keyword1' => ['value' => urlencode('男'),'color'=>'blue'],

'keyword2' => ['value' => urlencode('1993-10-23'),'color' => 'blue'],

'remark' => ['value' => urlencode('我的模板'),'color' => '#743A3A']

]

];

  • @param string $topcolor 模板内容字体颜色,不填默认为黑色

  • @return array

*/

public static function pushMessage($data = [],$topcolor = '#0000'){

$template = [

'touser' => $data['openid'],

'template_id' => $data['template_id'],

'url' => $data['url'],

'topcolor' => $topcolor,

'data' => $data['data']

];

$json_template = json_encode($template);

$url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" . self::getToken();

$result = self::curlPost($url, urldecode($json_template));

$resultData = json_decode($result, true);

return $resultData;

}

/**

  • addLog 日志记录

  • @param string $log_content 日志内容

*/

public static function addLog($log_content = ''){

$data = "";

$data .= "DATE: [ " . date('Y-m-d H:i:s') . " ]\r\n";

$data .= "INFO: " . $log_content . "\r\n\r\n";

file_put_contents('/Wchat.log', $data, FILE_APPEND);

}

/**

  • 发送get请求

  • @param string $url 链接

  • @return bool|mixed

*/

private static function curlGet($url){

$curl = curl_init();

curl_setopt($curl, CURLOPT_URL, $url);

curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);

curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);

curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

$output = curl_exec($curl);

if(curl_errno($curl)){

return 'ERROR ' . curl_error($curl);

}

curl_close($curl);

return $output;

}

/**

  • 发送post请求

  • @param string $url 链接

  • @param string $data 数据

  • @return bool|mixed

*/

private static function curlPost($url, $data = null){

$curl = curl_init();

curl_setopt($curl, CURLOPT_URL, $url);

curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);

curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);

if(!empty($data)){

curl_setopt($curl, CURLOPT_POST, 1);

curl_setopt($curl, CURLOPT_POSTFIELDS, $data);

}

curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

$output = curl_exec($curl);

curl_close($curl);

return $output;

}

}

/**

  • get_page_url 获取完整URL

  • @return url

*/

function get_page_url($type = 0){

$pageURL = 'http';

if($_SERVER["HTTPS"] == 'on'){

$pageURL .= 's';

}

$pageURL .= '://';

if($type == 0){

$pageURL .= $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];

}else{

$pageURL .= $_SERVER["SERVER_NAME"];

}

return $pageURL;

}

// 获取用户openid

$Wchat = new Wchat();

if(empty($_GET['code']) || !isset($_GET['code'])){

// 通过授权获取code

$url = get_page_url();

$authorize_url = $Wchat->getAuthorizeUrl($url);

header("Location:{$authorize_url}"); // 重定向浏览器

exit();

}else{

// 获取微信用户信息

$uid=session("uid");

$info=M("user")->where("uid=$uid")->find();

$openid=$info['openid'];

$list=M("good")->where("uid=$uid and fabu=2")->select();

foreach ($list as $key => $value) {

$good_id[]=$value['id'];

}

$where['shop_uid']=$uid;

$where['good_id']=array("in",$good_id);

$where['price_state']=1;

$res=M("good_pai_price")->where($where)->order("addtime desc")->limit(1)->find();

$id=$res['good_id'];

$mai_uid=$res['uid'];

$goodinfo=M("good")->where("id=$id")->find();

// echo $mai_uid;exit;

$userinfo=M("user")->where("uid=$mai_uid")->find();

// var_dump($goodinfo);exit;

$code = $_GET['code'];

$weiwei_token = $Wchat->getToken(); // 获取微信token

$user_info = $Wchat->getUserInfo($code, $weiwei_token);

// $openid = $user_info['openid'];

公众号消息推送

$Wchat::pushMessage([

'openid' => $openid, // 用户openid

'access_token' => $weiwei_token,

'template_id' => "", // 填写你自己的消息模板ID

'data' => [ // 模板消息内容,根据模板详情进行设置

'first' => ['value' => urlencode("尊敬的".$info['nickname'].",您好,您的拍品已有人出价。"),'color' => "#743A3A"],

'keyword1' => ['value' => urlencode($goodinfo['desc']),'color'=>'blue'],

'keyword2' => ['value' => urlencode(date("Y-m-d H:i",$res['addtime'])),'color'=>'blue'],

'keyword3' => ['value' => urlencode($userinfo['name']),'color' => 'green'],

'keyword4' => ['value' => urlencode($userinfo['s_province']),'color' => 'green'],

'keyword5' => ['value' => urlencode($res['price']/100),'color' => 'green'],

'remark' => ['value' => urlencode("更多出价详情,请点击页面进行实时查询。"),'color' => '#743A3A']

],

'url' => 'http://www.xxxx.com/Shop/info?id='.$id // 消息跳转链接

]);

}

  1. php调用接口代码

Php代码如下:

public function msg(){

require_once 'WchatAction.class.php';

// 微信接口类

$wchat = new \Wchat();

$wchat->pushMessage();

}

  好了,以上就是全部的源码了,如果大家还是存在不理解的地方,可以留言咨询。

  本文由专业的郑州小程序开发公司燚轩科技整理发布,原创不易,如需转载请注明出处!

收起阅读 »

UNI-Chat 简单配置 实现即时通讯

IM

群组:418967623

DOME:插件地址

架构全新更新  
支持分布式事务,集群  
如有问题可可留言  
运行环境 windows  
可配置: wss  
QQ:139939967
继续阅读 »

群组:418967623

DOME:插件地址

架构全新更新  
支持分布式事务,集群  
如有问题可可留言  
运行环境 windows  
可配置: wss  
QQ:139939967
收起阅读 »

百度语音识别应用申请教程

Speech

打开百度语音开放平台页面,登录后进入管理中心:

点击“创建应用”,进入“创建新应用”页面


应用名称:输入应用的名称,如“HelloH5”
应用类型:按平台提供的分类,选择应用所属的类型
选择接口:使用默认值(勾选了语音识别)即可,其它功能暂时未使用
语音包名:由于目前使用的是在线语音识别,勾选“不需要”即可
应用描述:输入应用的描述信息

完成输入后,点击“立即创建”,成功后进入“创建完毕”页面

点击“查看应用详情”,进入“应用详情”页面

这里可查看到AppID、API Key、Secret Key,其中Secret Key需要点击显示按钮才能查看完整内容。

继续阅读 »

打开百度语音开放平台页面,登录后进入管理中心:

点击“创建应用”,进入“创建新应用”页面


应用名称:输入应用的名称,如“HelloH5”
应用类型:按平台提供的分类,选择应用所属的类型
选择接口:使用默认值(勾选了语音识别)即可,其它功能暂时未使用
语音包名:由于目前使用的是在线语音识别,勾选“不需要”即可
应用描述:输入应用的描述信息

完成输入后,点击“立即创建”,成功后进入“创建完毕”页面

点击“查看应用详情”,进入“应用详情”页面

这里可查看到AppID、API Key、Secret Key,其中Secret Key需要点击显示按钮才能查看完整内容。

收起阅读 »

hcoder 祝大家国庆快乐,课程、产品全线优惠,graceUI 为uni-app量身打造的前端优秀框架持续更新中

graceUI uniapp

提前祝大家国庆节快乐!
现在起至十一期间,hcoder 所有收费课程9折【活动已经开启】
现在起至十一期间,hcoder 所有收费产品程9折【GraceUI、graceCms、graceWechat】
感谢大家对hcoder的支持!祝您及家人节日快乐,万事顺意 ^_^

graceUI (为uni-app及小程序量身定制的优秀前端框架)更新报告
2018-09-26 增加数据表格界面
2018-09-26 增加时间轴界面
2018-09-26 增加全屏分类选择界面
2018-09-28 增加购物界面【基于组件通讯机制 实现购物项目算法、总价统计算法】
21个基础组件+13个界面库,大幅度提高您的开发速度!!

相关站点:
课程 : www.hcoder.net
graceUI :grace.hcoder.net
phpGrace : www.phpGrace.com

继续阅读 »

提前祝大家国庆节快乐!
现在起至十一期间,hcoder 所有收费课程9折【活动已经开启】
现在起至十一期间,hcoder 所有收费产品程9折【GraceUI、graceCms、graceWechat】
感谢大家对hcoder的支持!祝您及家人节日快乐,万事顺意 ^_^

graceUI (为uni-app及小程序量身定制的优秀前端框架)更新报告
2018-09-26 增加数据表格界面
2018-09-26 增加时间轴界面
2018-09-26 增加全屏分类选择界面
2018-09-28 增加购物界面【基于组件通讯机制 实现购物项目算法、总价统计算法】
21个基础组件+13个界面库,大幅度提高您的开发速度!!

相关站点:
课程 : www.hcoder.net
graceUI :grace.hcoder.net
phpGrace : www.phpGrace.com

收起阅读 »

语音识别插件配置

Speech

概述

HBuilderX已支持讯飞语音识别和百度语音识别:

  • 讯飞语音识别
    无需配置SDK参数
    由于讯飞语音识别SDK绑定appid,云端打包只能固定使用DCloud申请的appid,虽然无需开发者向讯飞语音开放平台申请应用,但也导致无法在讯飞语音开放平台自定义应用个性化的高级语音识别参数配置。
    不支持自定义语音识别界面

  • 百度语音识别
    需要向百度语音开放平台申请AppID、API Key、Secret Key,详情可参考百度语音识别应用申请教程
    云端打包时在manifest.json中的“SDK配置”项中填入配置参数。
    支持自定义语音识别界面,参考HelloH5模板应用中Speech页面中的“自定义语音识别”源码

配置参数需要提交云端打包后才能生效,如果需要真机运行生效请使用自定义基座

HBuilderX中配置使用语音识别功能

从百度语音开放平台申请获取配置参数后,需在HBuilderX中配置并提交云端打包才能生效。
老版本HBuilder配置界面有差异,逻辑是一样的,建议更新使用HBuilderX

打开项目的manifest.json文件,在“App模块配置”项中勾选“Speech(语音输入,只能选一个)”:

注意:不能同时支持讯飞语音识别和百度语音识别,只可二选一

百度语音识别

在manifest.json文件“App模块配置”项的“Speech(语音输入,只能选一个)”下,勾选“百度语音识别”项,并输入从百度开放平台申请的参数:

  • appid:
    百度语音开放平台申请的AppID
  • apikey:
    百度语音开放平台申请的API Key
  • secretkey:
    百度语音开放平台申请的Secret Key

请到百度语音开放平台申请:https://console.bce.baidu.com/ai/

讯飞语音识别

在manifest.json文件“App模块配置”项的“Speech(语音输入,只能选一个)”下,勾选“讯飞语音识别”项:

注意:讯飞语音识别有识别次数限制,建议优先使用百度语音识别。

配置完成后Ctrl+S保存提交App云端打包生效。

继续阅读 »

概述

HBuilderX已支持讯飞语音识别和百度语音识别:

  • 讯飞语音识别
    无需配置SDK参数
    由于讯飞语音识别SDK绑定appid,云端打包只能固定使用DCloud申请的appid,虽然无需开发者向讯飞语音开放平台申请应用,但也导致无法在讯飞语音开放平台自定义应用个性化的高级语音识别参数配置。
    不支持自定义语音识别界面

  • 百度语音识别
    需要向百度语音开放平台申请AppID、API Key、Secret Key,详情可参考百度语音识别应用申请教程
    云端打包时在manifest.json中的“SDK配置”项中填入配置参数。
    支持自定义语音识别界面,参考HelloH5模板应用中Speech页面中的“自定义语音识别”源码

配置参数需要提交云端打包后才能生效,如果需要真机运行生效请使用自定义基座

HBuilderX中配置使用语音识别功能

从百度语音开放平台申请获取配置参数后,需在HBuilderX中配置并提交云端打包才能生效。
老版本HBuilder配置界面有差异,逻辑是一样的,建议更新使用HBuilderX

打开项目的manifest.json文件,在“App模块配置”项中勾选“Speech(语音输入,只能选一个)”:

注意:不能同时支持讯飞语音识别和百度语音识别,只可二选一

百度语音识别

在manifest.json文件“App模块配置”项的“Speech(语音输入,只能选一个)”下,勾选“百度语音识别”项,并输入从百度开放平台申请的参数:

  • appid:
    百度语音开放平台申请的AppID
  • apikey:
    百度语音开放平台申请的API Key
  • secretkey:
    百度语音开放平台申请的Secret Key

请到百度语音开放平台申请:https://console.bce.baidu.com/ai/

讯飞语音识别

在manifest.json文件“App模块配置”项的“Speech(语音输入,只能选一个)”下,勾选“讯飞语音识别”项:

注意:讯飞语音识别有识别次数限制,建议优先使用百度语音识别。

配置完成后Ctrl+S保存提交App云端打包生效。

收起阅读 »