UNIAPP----IOS端原生插件开发实战(一)

1.前言

在UNIAPP----Android端原生插件开发实战二进行了Android端的原生插件的开发,由于本业务同样需要IOS端的代理传输,所以下面介绍一下IOS端的原生插件开发过程。

2.工具材料清单

工具/材料 版本/版本名
HBuilder X 3.1.18
Xcode Version 12.1 (12A7403)
UNI-SDK [email protected]_20210609

3.原生环境配置

3.1创建插件工程

根据iOS平台uni原生插件开发教程,我们打开 Xcode,创建一个新的工程(Project),template 选择 Framework ,然后点击 Next。

根据文档描述,工程存放路径,建议直接存放在 iOSSDK目录中的 HBuilder-uniPluginDemo 插件开发主工程目录下,如下图所示,然后点击 Create

Project创建完成之后,删除掉自动创建的头文件,删除后的样子如下

然后选中工程名,在TARGETS->Build Settings中,将 Mach-O Type 设置为 Static Library如下图所示

然后将插件工程关闭,接下来需要将插件工程导入到插件开发主工程中。

3.2导入插件工程

打开 iOSSDK/HBuilder-uniPluginDemo工程目录,双击目录中的HBuilder-uniPlugin.xcodeproj文件运行插件开发主工程

在 Xcode 项目左侧目录选中主工程名,然后点击右键选择Add Files to “HBuilder-uniPlugin”

然后选择您刚刚创建的插件工程路径中,选中插件工程文件,勾选Create folder referencesAdd to targets两项,然后点击Add

这时在 Xcode 左侧目录中可以看到插件工程已经添加到了主工程中,如下图所示

3.3 工程配置

在 Xcode 项目左侧目录选中主工程名,在TARGETS->Build Phases->Dependencies中点击+

在弹窗中选中插件工程,如图所示,然后点击Add,将插件工程添加到Dependencies

然后在Link Binary With Libraries中点击+,同样在弹窗中选中插件工程,点击Add

此时可以看到 DependenciesLink Binary With Libraries都添加了插件工程,如下图所示

接下来需要在插件工程的Header Search Paths中添加开发插件所需的头文件引用,头文件存放在主工程的HBuilder-Hello/inc中,添加方法如下图所示,在 Xcode 项目左侧目录选中插件工程名,找到TARGETS->Build Settings->Header Search Paths双击右侧区域打开添加窗口,然后将inc目录拖入会自动填充相对路径,然后将模式改成recursive

4.SDK配置

SDK的库文件SecurePortal.framework是必须的,其包括了用户NBA的登录认证以及代理业务功能。
SecurePortal.framework包含两个头文件一个是SPNBAClient.hLibSecIDLite.h
SPNBAClient.h包含NBA的登录认证,代理和相关的接口。
LibSecIDLite.h是获取360ID的动态口令以及二维码授权等接口。

4.1.导入SDK文件

SDK文档中描述到:

App工程添加SecurePortal.framework的工程配置如下:
需要将动态库添加到Embeded BinariesLinked Frameworks and Libraries这两个选项里面。

再结合官网的描述

如果您的插件需要依赖第三方的SDK,开发阶段引入三方SDK的时候要引入到主工程,然后将三方SDK提供的 .h 头文件直接添加到插件工程中这样就可以正常调用三方SDK的Api了,功能开发完毕后在构建插件包的时候,需要将依赖的三方SDK库文件放到ios路径下,然后按照规范编辑 package.json;

因此,先进行第一步,将SecurePortal.framework添加到iosTunnel.xcodeproj
为方便引用,先在目录下新建一个Frameworks目录

然后将SecurePortal.framework拷贝到这个目录下面,如下图所示

拷贝成功后可以同时看到Build Phases里面也有了这个库文件的link

framework引入完毕后,接下来在主工程对SDK进行引用
选中工程,如图所示,然后在Link Binary With Libraries点击+

会发现没有看到这个SecurePortal.framework,这时候选择下面的Add Files

选择我们放到iosTunnel目录下面的SecurePortal.framework

image.png

然后在Embed Frameworks处同样添加SecurePortal.framework

4.2业务代码实现

新建头文件和.m文件,如下图所示(直接选择新建cocopods class可以同时生成.h和.m文件)

存放到iosTunnel目录下

开始业务代码的实现,头文件中先把官方文档的部分抄过来,在引入SDK的头文件

//tunnel.h
#import 
// 引入 DCUniModule.h 头文件
#import "DCUniModule.h"
#import 
@interface tunnel : DCUniModule
@property (nonatomic, strong) UniModuleKeepAliveCallback callback;
@end

这几行代码引入过后,等待IDE编译小半分钟(此时Xcode不会提示你它正在编译),如果对着SPNBAClient等类右键能够跳转到定义的话就说明头文件引入成功了。

下面进行方法的实现

//tunnel.m
#import "tunnel.h"

@interface tunnel()

typedef void (^CompletioBlock)(NSDictionary *dic, NSURLResponse *response, NSError *error);
typedef void (^SuccessBlock)(NSDictionary *data);
typedef void (^FailureBlock)(NSError *error);

@end
@implementation tunnel

UNI_EXPORT_METHOD(@selector(connectNBA:callback:))
// 通过宏 UNI_EXPORT_METHOD 将异步方法暴露给 js 端
//UNI_EXPORT_METHOD(@selector(testAsyncFunc:callback:))
/// 异步方法(注:异步方法会在主线程(UI线程)执行)
/// @param options js 端调用方法时传递的参数
/// @param callback 回调方法,回传参数给 js 端
- (void)connectNBA:(NSDictionary *)options callback:(UniModuleKeepAliveCallback)callback {
    //    NSLog(@"传递过来的参数是%@",options);
    self.callback = callback;
    NSString* NBA_host = @"xxx.xxx.xxx.xx";
    NSString* NBA_port = @"xxx";
    NSString* auth_username = options[@"NBAUsername"];
    NSString* auth_password = options[@"NBAPassword"];
    NSDictionary *loginDic = @{
        @"NBA_host"      : NBA_host,
        @"NBA_port"      : NBA_port,
        //        @"auth_server"   : @"认证服务器名,默认选取第一个",
        @"auth_username" : auth_username,
        @"auth_password" : auth_password,
        @"auth_mode"     : @0, //0用户名密码登录,1,证书登录, 2 动态口令, 3 二维码
        @"auth_autologin": @1, //1自动登录,0手动登录,需要实现登录界面
        //        @"extra_xxxxxx" :  extra_ 开头的额外的参数
    };
    NSLog(@"loginDic%@",loginDic);
}

- (void)didLoginSuccess {
    NSLog(@"登录成功");
    self.callback(@"隧道登录成功", NO);
}
- (void)onLoginErrorID:(NSInteger)errid msg:(NSString*)errmsg {
    if (self.callback)
    {
        NSLog(@"失败信息---%@",errmsg);
        self.callback(errmsg, NO);
    }
}

// 通过宏 UNI_EXPORT_METHOD_SYNC 将同步方法暴露给 js 端
UNI_EXPORT_METHOD_SYNC(@selector(get:callback:))
- (void)get:(NSDictionary *)options callback:(UniModuleKeepAliveCallback)callback {
    NSString *urlString = options[@"url"];
    NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"GET"];
    NSDictionary *proxyConfigDic = nil;
    NSInteger proxyPort = [SPNBAClient queryProxyPort];
    //NSLog(@"端口=%ld",proxyPort);
    if(proxyPort)
    {
        NSString *host = @"xxx.x.x.x";
        proxyConfigDic = @{(NSString*)kCFStreamPropertyHTTPProxyHost: host,
                           (NSString*)kCFStreamPropertyHTTPProxyPort: @(proxyPort),
                           (NSString*)kCFNetworkProxiesHTTPEnable:@YES,
                           (NSString*)kCFStreamPropertyHTTPSProxyHost: host,
                           (NSString*)kCFStreamPropertyHTTPSProxyPort:@(proxyPort)
        };
    }
    NSURLSessionDataTask* sessionTask = [self   createSessionWithRequest:request                                          withProxyConfig:proxyConfigDic
                   options:options
                    callback:callback];
    [sessionTask resume];
}

// 通过宏 UNI_EXPORT_METHOD_SYNC 将同步方法暴露给 js 端
UNI_EXPORT_METHOD_SYNC(@selector(post:callback:))
- (void)post:(NSDictionary *)options callback:(UniModuleKeepAliveCallback)callback {
    NSString *urlString = options[@"url"];
    NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    request.HTTPMethod = @"POST";
    NSDictionary *proxyConfigDic = nil;
    NSInteger proxyPort = [SPNBAClient queryProxyPort];
    NSLog(@"url=%@",url);
    NSLog(@"端口=%ld",proxyPort);
    if(proxyPort)
    {
        NSString *host = @"xxx.x.x.x";
        proxyConfigDic = @{(NSString*)kCFStreamPropertyHTTPProxyHost: host,
                           (NSString*)kCFStreamPropertyHTTPProxyPort: @(proxyPort),
                           (NSString*)kCFNetworkProxiesHTTPEnable:@YES,
                           (NSString*)kCFStreamPropertyHTTPSProxyHost: host,
                           (NSString*)kCFStreamPropertyHTTPSProxyPort:@(proxyPort)
        };
    }
    NSURLSessionDataTask* sessionTask = [self createSessionWithRequest:request                                                    withProxyConfig:proxyConfigDic
                                         options:options
                                         callback:callback];
    [sessionTask resume];
}

- (NSURLSessionDataTask*)createSessionWithRequest:(NSURLRequest*)aRequest
                                  withProxyConfig:(NSDictionary*)proxyConfigDic
                                          options: (NSDictionary *)options
                                         callback:(UniModuleKeepAliveCallback)callback
{
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
    config.connectionProxyDictionary = proxyConfigDic;
    if([options objectForKey:@"token"])
    {
        NSLog(@"token=%@",options[@"token"]);
        config.HTTPAdditionalHeaders = @{@"token":options[@"token"]};
    }
    NSURLSession *session = [NSURLSession sessionWithConfiguration:config
                                                          delegate:self
                                                     delegateQueue:nil];
    NSURLSessionDataTask *sessionTask = [session dataTaskWithRequest:aRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if(error)
        {
            NSLog(@"请求错误:%@",[error localizedDescription]);
            callback([error localizedDescription], NO);
        }
        else
        {
            NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"请求成功:%@",dataStr);
            callback(dataStr, NO);
        }
    }];
    return sessionTask;
}
@end

5.原生应用测试

5.1 编写UNI端业务代码




编写完成后,右键UNI项目: 发行-原生APP本地打包-生成本地打包APP资源

打开APP资源路径,然后删除掉HBuilder-uniPlugin/HBuilder-Hello/Pandora/apps/_UNI_33C5A38/www这个WWW文件夹,然后把生成的离线WWW文件拷贝过去。

资源文件拷贝完毕后,选中工程中的HBuilder-uniPlugin-Info.plist文件右键->Open As->Source Code找到dcloud_uniplugins节点,copy下面的内容添加到dcloud_uniplugins节点下,按您插件的实际信息填写对应的项

编写plist文件完毕后,选择HBuilder这个target后,插上真机,command+B后等待一段时间即可进行测试。

6.插件打包

测试完毕之后,首先生成iosTunnel.Framework文件,

再选中iosTunnel,command+B进行framework文件编译生成

生成完成后,将第三方SDK库文件与我们自己写生成的库文件放置为如下目录

//package.json
{
    "name": "原生插件",
    "id": "NBATunnel",
    "version": "1.0",
    "description": "原生插件",
    "_dp_type":"nativeplugin",
    "_dp_nativeplugin":{
        "ios": {
            "plugins": [{
                "type": "module",
                "name": "NBATunnel-NBATunnel",
                "class": "NBATunnel"
            }],
            "frameworks": ["SecurePortal.framework"],
            "integrateType": "framework",
            "deploymentTarget": "9.0"
        }
    }
}

然后再manifest.json选择本地插件,提交云端打包即可。

你可能感兴趣的:(UNIAPP----IOS端原生插件开发实战(一))