集成 MPWeex 到 iOS

使用CocoaPods可以方便的将MPWeex集成到自己的项目中, 也可以手动将MPWeex集成到自己的项目中。

1. CocoaPods

从CocoaPods仓库中获取MPWeex的最新版本。

将MPWeex依赖添加到你的Podfile文件中:

source 'git@github.com:CocoaPods/Specs.git'
target 'YourTarget' do
    platform :ios, '8.0'
    pod 'MPWeexSDK', '0.28.0'
end

运行 pod install 命令安装依赖。

2. 手动集成

从GitHub仓库中获取MPWeex的最新版本。

将MPWeexSDK文件夹添加到你的项目中。

libc++libiconvlibresolvlibz库添加到你的项目中。

CoreServices, AVFoundation, AVKit, CoreMedia, CoreTelephony, GLKit, JavaScriptCore, MediaPlayer, Security, SystemConfiguration, WebKit框架添加到你的项目中。

将第三方库依赖添加到你的Podfile文件中:

source 'git@github.com:CocoaPods/Specs.git'
target 'YourTarget' do
    platform :ios, '8.0'
    pod 'GZIP', '~> 1.2'
    pod 'SSZipArchive'
    pod 'AliyunOSSiOS'
    pod 'YYModel'
    pod 'yismcore', '~> 0.1.0'
end

运行 pod install 命令安装依赖。

3. 初始化SDK

APP商户入驻成功后,系统会分配APPID、License和白盒密码算法密钥mpweex.bmp,将mpweex.bmp添加到工程目录中。

建议在 didFinishLaunchingWithOptions 回调中初始化MPWeex。

// 初始化MPWeex
[[MPWeexSDKManager sharedInstance] initialize];
[[MPWeexSDKManager sharedInstance] setAppID:@"your mpweex appid."
                                    license:@"your mpweex license."];
[[MPWeexSDKManager sharedInstance] setBasePath:@"mpweex api host."];

4. 扩展图片加载

MPWeex不提供图片加载能力。自定义图片加载,需要实现WXImgLoaderProtocol协议。

参见:WXImageProtocolImpl

#import "WXImageProtocolImpl.h"
#import <MPWeexSDK/WXUtility.h>
#import <YYWebImage/YYWebImageManager.h>

@implementation WXImageProtocolImpl

- (id<WXImageOperationProtocol>)downloadImageWithURL:(NSString *)url
                                          imageFrame:(CGRect)imageFrame
                                            userInfo:(NSDictionary *)options
                                           completed:(void(^)(UIImage *image, NSError *error, BOOL finished))completedBlock {
    if ([WXUtility isBlankString:url]) {
        return nil;
    }
    
    if (!completedBlock) {
        return nil;
    }
    
    // 正则表达式匹配base64图片
    NSArray *matchesResults = [self matchesBase64Image:url];
    if (matchesResults && matchesResults.count > 0) {
        NSTextCheckingResult *matchesResult = matchesResults.firstObject;
        NSString *type = [url substringWithRange:[matchesResult rangeAtIndex:2]];
        NSString *imageBaseCode = [url substringWithRange:[matchesResult rangeAtIndex:3]];
        
        // base64 image
        if ([type isEqualToString:@"base64"] && ![WXUtility isBlankString:imageBaseCode]) {
            [self loadBase64ImageWithImageBaseCode:imageBaseCode completed:completedBlock];
        }
    } else {
        if ([url hasPrefix:@"//"]) {
            // ordinary network image
            [self loadImageWithUrl:[NSString stringWithFormat:@"http:%@", url] completed:completedBlock];
        } else {
            if ([[NSURL URLWithString:url].scheme isEqualToString:@"file"]) {
                // local image
                NSString *imagePath = [url stringByReplacingOccurrencesOfString:@"file:///" withString:@""];
                [self loadLocalImageWithFilePath:imagePath completed:completedBlock];
            } else {
                // oss image
                [self loadOSSImageWithUrl:url completed:completedBlock];
            }
        }
    }
    
    return nil;
}

- (NSArray *)matchesBase64Image:(NSString *)url {
    NSString *pattern = @"^data:image/(.*?);(.*?),(.*)$";
    NSRegularExpression *regularExpression = [NSRegularExpression regularExpressionWithPattern:pattern
                                                                                       options:NSRegularExpressionCaseInsensitive
                                                                                         error:NULL];
    return [regularExpression matchesInString:url
                                      options:NSMatchingReportCompletion
                                        range:NSMakeRange(0, url.length)];
}

- (void)loadImageWithUrl:(NSString *)url
               completed:(void(^)(UIImage *image, NSError *error, BOOL finished))completedBlock {
    [[YYWebImageManager sharedManager] requestImageWithURL:[NSURL URLWithString:url]
                                                   options:YYWebImageOptionSetImageWithFadeAnimation
                                                  progress:nil
                                                 transform:nil
                                                completion:^(UIImage * _Nullable image, NSURL * _Nonnull url, YYWebImageFromType from, YYWebImageStage stage, NSError * _Nullable error) {
        if (!error && image) {
            completedBlock(image, nil, YES);
        } else {
            completedBlock(nil, [self errorWithDescription:@"load image failed."], YES);
        }
    }];
}

- (void)loadOSSImageWithUrl:(NSString *)url
                  completed:(void(^)(UIImage *image, NSError *error, BOOL finished))completedBlock {
    [[YYWebImageManager sharedManager] requestImageWithURL:[NSURL URLWithString:url]
                                                   options:YYWebImageOptionSetImageWithFadeAnimation
                                                  progress:nil
                                                 transform:nil
                                                completion:^(UIImage * _Nullable image, NSURL * _Nonnull url, YYWebImageFromType from, YYWebImageStage stage, NSError * _Nullable error) {
        if (!error && image) {
            completedBlock(image, nil, YES);
        } else {
            completedBlock(nil, [self errorWithDescription:@"load oss image failed."], YES);
        }
    }];
}

- (void)loadBase64ImageWithImageBaseCode:(NSString *)imageBase64Code
                               completed:(void(^)(UIImage *image, NSError *error, BOOL finished))completedBlock {
    NSData *imageData = [[NSData alloc] initWithBase64EncodedString:imageBase64Code options:0];
    UIImage *image = [UIImage imageWithData:imageData];
    if (image) {
        completedBlock(image, nil, YES);
    } else {
        completedBlock(nil, [self errorWithDescription:@"load base64 image failed."], YES);
    }
}

- (void)loadLocalImageWithFilePath:(NSString *)filePath
                         completed:(void(^)(UIImage *image, NSError *error, BOOL finished))completedBlock {
    if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
        UIImage *image = [UIImage imageWithContentsOfFile:filePath];
        if (image) {
            completedBlock(image, nil, YES);
        } else {
            completedBlock(nil, [self errorWithDescription:@"load local image failed."], YES);
        }
    } else {
        completedBlock(nil, [self errorWithDescription:@"load local image failed, image file does not exist."], YES);
    }
}

- (NSError *)errorWithDescription:(NSString *)errorDescription {
    return [NSError errorWithDomain:WX_ERROR_DOMAIN
                               code:-1
                           userInfo:@{NSLocalizedDescriptionKey : errorDescription}];
}

@end

4.1 修改初始化参数

// 初始化MPWeex
[[MPWeexSDKManager sharedInstance] initialize];
[[MPWeexSDKManager sharedInstance] setAppID:@"your mpweex appid."
                                    license:@"your mpweex license."];
[[MPWeexSDKManager sharedInstance] setBasePath:@"mpweex api host."];
// 注册自定义图片加载协议实现
[[MPWeexSDKManager sharedInstance] registerHandler:[WXImageProtocolImpl new] withProtocol:@protocol(WXImgLoaderProtocol)];

5. 登录信息同步

APP内,如果要完全支持小程序功能,用户需要在小程序平台进行登录信息同步。在用户登录成功或用户资料有更新时,调用此接口。

TIP

此接口是幂等的,可重复调用,平台内只会进行一次用户信息登记。后续调用平台将会进行用户资料的同步操作。

接口描述

/// 登录成功后,将用户信息同步至小程序平台
/// @param platformUID APP商户应用的用户ID
/// @param phoneNo APP商户应用的用户手机号码
/// @param callback 回调
- (void)loginWithPlatformUID:(NSString *)platformUID
                     phoneNo:(NSString *)phoneNo
           completionHandler:(WXOpenAccountCallback)callback;

DEMO

[[MPWeexSDKManager sharedInstance] 
               loginWithPlatformUID:@"your app useridentity"
                            phoneNo:@"your app user phone number"
                  completionHandler:^(BOOL sucessed, NSError *error) {
    // your code if needed.
}];

6. 退出登录通知接口

APP内,如果退出登录了,需要调用此接口通知SDK,以进行登录状态的同步。

/// 退出登录时,通知SDK
- (void)logout;

DEMO

// 通知SDK退出登录
[[MPWeexSDKManager sharedInstance] logout];

7. 判断APP用户是否登录

因为大部分小程序都是需要用户登录后,才可以访问的,故需要APP实现IWXUserInfoAdapter告之小程序SDK,用户是否已登录成功。

TIP

主要实现ensureLogged,getUserInfo忽略

此适配器主要用于APP定制登录跳转或友好提示。

接口示例:

#import <UIKit/UIKit.h>
#import <MPWeexSDK/WXUserInfoProtocol.h>

@interface WXUserInfoProtocolImpl : NSObject <WXUserInfoProtocol>
/// 获取APP用户信息
- (WXUserInfoModel *)getUserInfo;

/// 确保用户已经登录
/// @param sourceViewController 源控制器
- (BOOL)ensureLoggedWithSourceViewController:(UIViewController *)sourceViewController;
@end


#import "WXUserInfoProtocolImpl.h"
#import <MPWeexSDK/WXUserInfoModel.h>

@implementation WXUserInfoProtocolImpl

- (WXUserInfoModel *)getUserInfo {
    // deprecated, ignore it.
    return nil;
}

// 用于判断APP用户是否已登录,请将方法内逻辑替换为APP判断用户是否已登录的逻辑。
- (BOOL)ensureLoggedWithSourceViewController:(UIViewController *)sourceViewController {
    // APP用户登录状态
    BOOL logined = YES;
    
    if (logined) {
        // 用户已登录则直接返回true
        return true;
    } else {
        // 跳转实现
        return false;
    }
}
@end
  • ensureLoggedWithSourceViewController: 此方法用于判断用户是否已经登录,因为大部分小程序都是需要用户登录后方可操作的。

7.1 修改初始化参数

// 初始化MPWeex
[[MPWeexSDKManager sharedInstance] initialize];
[[MPWeexSDKManager sharedInstance] setAppID:@"your mpweex appid."
                                    license:@"your mpweex license."];
[[MPWeexSDKManager sharedInstance] setBasePath:@"mpweex api host."];
// 注册自定义用户协议实现
[[MPWeexSDKManager sharedInstance] registerHandler:[WXUserInfoProtocolImpl new] withProtocol:@protocol(WXUserInfoProtocol)];

8. SDK其它API使用方法

8.1 跳转至指定小程序

在APP中,可通过MPID跳转到指定的小程序。

  • 接口
/// 跳转至小程序
/// @param sourceViewController 源控制器
/// @param mpID 小程序ID
/// @param logo 小程序图标
/// @param systemType 小程序系统类型 0宿主、1普通、 2游戏
/// @param offlineSupportType 是否支持离线访问 0不支持、1支持 不支持离线访问的,需要先登录
- (void)presentMPViewControllerWithSourceViewController:(UIViewController *)sourceViewController
                                                   mpID:(NSString *)mpID
                                                   logo:(NSString *)logo
                                             systemType:(WXMPSystemType)systemType
                                     offlineSupportType:(WXMPOfflineSupportType)offlineSupportType;
  • 调用示例
[[MPWeexSDKManager sharedInstance] presentMPViewControllerWithSourceViewController:self
    mpID:@"MPAAABa7vz87hIvbIAq1lG"  // MPID
    logo:@"images/AAFLlQAAAWzlpHpnAgI" // MP LOGO
    systemType:WXMPSystemTypeNormal // MP TYPE 默认WXMPSystemTypeNormal
    offlineSupportType:WXMPOfflineSupportTypeNotCan]; // 是否支持离线访问

8.2 跳转至指定页面

在APP中,可通过SDK跳转到指定的小程序页面。

  • 接口
/// 跳转到指定页面
/// @param sourceViewController 源控制器
/// @param page 指定页面
- (void)presentMPPageWithSourceViewController:(UIViewController *)sourceViewController mpPage:(WXMPPage)page;
  • 页面参数
typedef struct {
    NSString *page;
    NSString *pageTitle;
} WXMPPage;
static const WXMPPage kPageIndex        = {@"/default.js", @"众圈"};
static const WXMPPage kPageRecent       = {@"/pages/wxmp.js", @"最近使用"};
static const WXMPPage kPageMymp         = {@"/pages/minemp.js", @"我关注的"};
static const WXMPPage kPageRecommend    = {@"/pages/recommendmp.js", @"推荐的"};
static const WXMPPage kPageSearch       = {@"/pages/search.js", @"搜索"};
  • 调用示例
[[MPWeexSDKManager sharedInstance] presentMPPageWithSourceViewController:self
                                                                 mpPage:kPageIndex];