WADE移动应用框架帮助文档

整个移动应用框架是采用Hybrid模式构建,分为H5端和原生端。就目前适应CRM复杂又经常变动的业务,我们以H5为主,原生为辅的形式构建我们的app。H5端采用原生控件webview承接,原生端对应的平台各自研发承接。既然是由两部分构成,就需要一种框架能支持两者之间的交互。仔细研究Android和iOS这两个平台的webview控件的源码和内核,它们都支持一种叫”语言穿梭机”的机制:Android可从Java对象穿梭到JS中构造成JS对象,反之亦然;iOS可从OC对象穿梭到JS中构成JS对象,反之也亦然。只是在Android端是系统类支持的,而iOS端需要从webview内核中遍历出这个穿梭机的上下文对象,在这个穿梭机的上下文对象中注册Java对象,进而穿梭到H5中变成JS对象;

一、H5端接入步骤

1、为兼容PC需引入plugin.js

此js对原生插件API做一个PC端的API的映射,目前我们给一个基础的插件API样例JS,可根据项目的需要增加插件接口,plugin.js内容如下:


$(document).ready(function(){

    mboss.noTerminal = {
        error: function(){
            alert('请在手机终端运行此方法');
            return false;
        },
        returnEmptyStr: function(){
            return '';
        }, 
    };
    /* 框架相关方法兼容 */
    if (!window.ExtendScriptPlugin){
        window.ExtendScriptPlugin = {};
        ExtendScriptPlugin.JN_Photograph = mboss.noTerminal.error;//拍照

        /* 本地存储 */
        //localStorage操作
        mboss.storage = {
            get: function(name){
                return window.localStorage.getItem(name) || '';
            },
            set: function(name, value){
                window.localStorage.setItem(name, value);
            },
            remove: function(name){
                window.localStorage.removeItem(name); 
            },
            clear:function(){
                window.localStorage.clear();
            }
        };

        ExtendScriptPlugin.JN_GetValueWithKey = mboss.storage.get;
        ExtendScriptPlugin.JN_SetValueWithKey = mboss.storage.set;
        ExtendScriptPlugin.JN_RemoveAllData = mboss.storage.clear;
        ExtendScriptPlugin.JN_RemoveDataByKey = mboss.storage.remove;
    }
});

(1)第14行的ExtendScriptPlugin就是原生插件对象;
(2)以JN_开头的API就是插件的原生API, 在plugin.js中我们做一个PC端API的映射,例如,JN_Photograph 在PC端就映射成mboss.noTerminal.error。如果应用运行在手机端,就会调用原生API:JN_Photograph。
(3)第35-38是做数据存储的函数的映射

2、在H5页面中调用原生接口

假定原生定义的JN_Photograph如下:

- (void)JN_Photograph:(NSString*)functionName;

1)非iframe页面中使用

请使用window对象引用插件对象:

window.ExtendScriptPlugin.JN_Photograph('callbackFunctionName');

2)在iframe页面中使用

请使用top对象引用插件对象:

top.ExtendScriptPlugin.JN_Photograph('callbackFunctionName');

3、js回调函数的处理

目前我们是采用给原生接口传入回调函数名的方式实现JS回调,如上面的JN_Photograph。后面我们会支持JS匿名函数的回调方式。

二、原生端接入步骤

1、iOS平台接入步骤

1)引入AIBase.framework框架包

2)定义插件接口穿梭协议

此协议继承自系统的穿梭协议JSExport。 在协议中定义插件提供给H5端调用的原生API,如图所示我们定义的插件基类的穿梭协议:

/**
 *  扩展插件类
 *  1、JSExport是JS与OC之间的穿梭机;
 *  2、把需要扩展的API定义到protocol:JSExport里,在插件类里实现接口;
 *  3、若是多参数的API,可以采用JSExportAs来声明接口,可以参考ScriptPluginBase;默认的情况,在JS端是会把参数tag首字母大写拼接成JS的function调用方式,例如:test:(NString*)str key:(NString*)k --> testKey(str,k);
 *  4、注意,扩展的API,如果要操作UI的,一定要在主线程里调用。很多情况,jscontext是非主线程调用API;
 */

@protocol JN_BasePluginExport <JSExport>

// 基础的能力接口
// 1、数据存取
JSExportAs(JN_SetValueWithKey,- (void)JN_SetValueWithKey:(NSString*)key value:(NSString*)value);
- (NSString*)JN_GetValueWithKey:(NSString*)key;
- (void)JN_RemoveAllData;
- (void)JN_RemoveDataByKey:(NSString*)key;

// 2、数据安全
- (NSString*)JN_Encrypt:(NSString*)context;
- (NSString*)JN_Decrypt:(NSString*)encrypt;
- (NSString*)JN_IDMD5:(NSString*)userName;
- (NSString*)JN_Token:(NSString*)params;
JSExportAs(JN_ShowFadeMsg, -(void)JN_ShowFadeMsg:(NSString *)msg status:(int)status);

// 隐藏键盘
- (void)JN_HideKeyboard;
// 获取手机型号等信息
- (NSString *)JN_GetPhoneModule;
@end

由于OC与JS定义函数的语法不同,针对有多个入参的函数,应该采用JSExportAs做函数语法的映射,如上图的 JN_SetValueWithKey,它在JS中的定义为:

function JN_SetValueWithKey(key,value); 

在OC中定义为:

- (void)JN_SetValueWithKey:(NSString*)key value:(NSString*)value;

为了后面的讲述,我们假设插件定义的穿梭协议:

@protocol JN_ExtendPluginExport <JSExport>
@end

3)继承插件的基类:AIWebViewBasePlugin

假设子类的类名为:ExtendScriptPlugin

4)实现穿梭协议

插件类需要实现穿梭协议定义的API:

@interface ExtendScriptPlugin : AIWebViewBasePlugin<JN_ExtendPluginExport>
@end

请在ExtendScriptPlugin中实现JN_ExtendPluginExport中定义的函数。注意:在实现穿梭协议的函数的时候,如果该函数有操作UI,包括H5和原生的UI元素的操作,请在UI主线程中执行这些代码 如下面的代码所示:

- (void)JN_Photograph:(NSString*)functionName {
    __weak CRMMainVC *vc = (CRMMainVC*)self.vc;
    dispatch_async(dispatch_get_main_queue(), ^{
        [vc JN_Photograph:functionName];
    });
}

上面dispatch_async就是iOS平台推荐的主线程中执行代码的标准写法,这样[vc JN_Photograph:functionName]就会在UI主线程中执行。

5)配置H5插件

为了配置文件通用性,我们iOS和android采用同一种xml格式的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<plugins>
    <plugin name="ExtendScriptPlugin" class="com.ai.crmapp.ExtendScriptPlugin" packageName="com.ai.crmapp"></plugin>
</plugins>

配置中我们可以配置多个plugin。这里仅配置一个,即上面定义的ExtendScriptPlugin。对于iOS平台class和packageName两个字段是无效的。假定我们的配置文件为:h5Plugin.xml。

6)向WebView内核中注册H5插件

在我们框架中提供插件引擎类:AIWebViewPluginEngine。它目前主要两个能力:一、注册上述配置的H5插件;二、调用H5的JS 函数;

(1)注册H5插件

- (void)registerH5Engine:(UIWebView*)webView {
    NSData *configData = [[AIPluginTools SharedObj] roadResWithName:@"h5Plugin.xml"];
    AIWebViewPluginEngine *engine = [AIWebViewPluginEngine SharedObj];
    [engine registerPluginsInVC:self webView:webView configData:configData];
}

上述代码读取插件配置文件h5Plugin.xml,然后通过通过插件引擎在webview上注册插件。

(2)通过引擎调用H5的JS

我们的回调JS函数以及原生需要调用H5的JS函数都可通过引擎调用H5的JS

dispatch_async(dispatch_get_main_queue(), ^{
                NSString *js = [NSString stringWithFormat:@"%@('%@')",@"JS_SetScanResult",result];
                AIWebViewPluginEngine *engine = [AIWebViewPluginEngine SharedObj];
                [engine excuteJavascript:js];
            });

上述对象js即我们需要调用H5中的JS。这里我们也采用在主线程中执行调用(因为这个执行的JS会操作H5的图片展示控件)

2、android平台接入步骤

1)引入框架jar包

请在android studio中引入我们的框架包 aibase.jar和wade-data.jar。

2)继承插件的基类:AIWebViewBasePlugin

假设子类的类名为,ExtendScriptPlugin:

/**
 * Created by wuyoujian on 2017/5/4.
 */

public class ExtendScriptPlugin extends AIWebViewBasePlugin {

3)定义H5调用的原生接口

在Android平台定义一个H5调用的原生接口只需要做的两点:一、是public的函数;二、需要增加注解:@JavascriptInterface。如下面的一个插件函数:

// 拍照
    @JavascriptInterface
    @NotProguard
    public void JN_Photograph(String functionName) {
        final String  mFunctionName = functionName;
        final String checkPermissinos [] = {Manifest.permission.CAMERA,
                Manifest.permission.WRITE_EXTERNAL_STORAGE};
        PermissionUitls.mContext = getActivity();
        if(!PermissionUitls.isGetAllPermissionsByList(checkPermissinos) ) {
            new AlertDialog
                    .Builder(getActivity())
                    .setTitle("提示信息")
                    .setMessage("该功能需要您接受应用对一些关键权限(拍照)的申请,如之前拒绝过,可到手机系统的应用管理授权设置界面再次设置。")
                    .setPositiveButton("确认", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            checkPermission(mFunctionName,PermissionUitls.PERMISSION_CAMERA_CODE,checkPermissinos);
                        }
                    }).show();
        } else {

            jumpToRectCameraActivity(functionName);
        }
    }

4)配置H5插件

为了配置文件通用性,我们iOS和android采用同一种xml格式的配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<plugins>
    <plugin name="ExtendScriptPlugin" class="com.ai.crmapp.ExtendScriptPlugin" packageName="com.ai.crmapp"></plugin>
</plugins>

配置中我们可以配置多个plugin。这里仅配置一个,即上面定义的ExtendScriptPlugin。对于iOS平台class和packageName两个字段是无效的。假定我们的配置文件为:h5Plugin.xml。

5)向WebView内核中注册H5插件

在我们框架中提供插件引擎类:AIWebViewPluginEngine。它目前主要两个能力:一、注册上述配置的H5插件;二、调用H5的JS 函数;

(1)注册H5插件

private void setH5PluginEngine() {
        AIWebViewPluginEngine_dl engine = AIWebViewPluginEngine_dl.getInstance();
        engine.registerPlugins(this, mWebView, mPluginCfgFile);
    }

mWebView是webview控件,mPluginCfgFile 就是上述定义的插件配置文件: h5Plugin.xml,这个配置文件请放在assets里,如图所示:
这里写图片描述

(2)通过引擎调用H5的JS

我们的回调JS函数以及原生需要调用H5的JS函数都可通过引擎调用H5的JS。

runOnUiThread(new Runnable() {
                        @Override
                        public void run() {

                            AIWebViewPluginEngine_dl engine = AIWebViewPluginEngine_dl.getInstance();
                            String JS = String.format("%s('%s','%s')","JS_LaunchApp_callback","0","");
                            engine.excuteJavascript(JS, new ValueCallback<String>() {
                                @Override
                                public void onReceiveValue(String value) {
                                    LogUtil.d("jsMethod",value);
                                }
                            });
                        }
                    });

同理,在插件函数里如果会牵涉到操作UI元素(包括原生和H5)都需要在UI主线程中执行,如上面的runOnUiThread

三、框架提供的能力

目前iOS平台提供比较全面支撑crm的能力,android目前提供的部分能力,后面会根据iOS平台以及业务的需求两个平台能力做的一致。

1、iOS平台提供的能力

1)自定义证件拍照控件类AICaptureView

范例:

//243px x 153px
    CGFloat width = 200 * 243 / 153;
    CGRect markFrame = CGRectMake((self.view.frame.size.width - width)/2.0, 184, width, 200);
    AICaptureView *captureView = [[AICaptureView alloc] initWithFrame:self.view.bounds];
    self.captureView = captureView;
    [_captureView cropRectForInterest:markFrame];
    [self.view addSubview:captureView];

上述cropRectForInterest设置证件拍照的区域框。

2)手写控件类SignatureView

控件中提供了画笔的基本的操作:笔的大小、笔的颜色、撤销一笔、重做一笔、清除所有笔画、保存签名图片。
范例:

__weak SignatureViewController *wSelf = self;
    self.signView = [[SignatureView alloc] initWithFrame:CGRectMake(0, [DeviceInfo navigationBarHeight], self.view.frame.size.width, [DeviceInfo screenHeight] - [DeviceInfo navigationBarHeight] - 44) status:^(SigntureStatus status) {
        //
        SignatureViewController *sSelf = wSelf;
        if (status == SignatureStatusBegin) {
            [sSelf.undoItem setEnabled:YES];
        }
    }];

    [_signView setPenSize:3.0];
    [self.view addSubview:_signView];

3)手势密码控件类AIGesturePasswordView

范例:

// 创建控件
_passwordView = [[AIGesturePasswordView alloc] initWithFrame:CGRectMake(0, 120, self.view.frame.size.width,  self.view.frame.size.height - 60 - 120)];
    [_passwordView setDelegate:self];
    [_passwordView setDefaultColor:[UIColor blackColor]];
    [_passwordView setPathColor:[UIColor colorWithHex:0x378FC9]];
    [_passwordView setSelectColor:[UIColor colorWithHex:0x378FC9]];
    [_passwordView setWrongColor:[UIColor redColor]];
    [self.view addSubview:_passwordView];

// 实现手势控件回调
#pragma mark - AIGesturePasswordViewDelegate
// 通过手势设置密码
- (void)gesturePasswordView:(AIGesturePasswordView*)sender password:(NSString*)password {
}
// 密码个数小于4位,无效
- (void)gestureInvalidPasswordView:(AIGesturePasswordView*)sender {

}

4)扫码控件类QRViewController

范例:

QRViewController *qrController = [[QRViewController alloc] init];
    [picker presentViewController:qrController animated:YES completion:^{
        //
        [qrController startScanQRCodeWithFinish:^(NSString *result, QRCodeScanStatus status) {
            //
            [picker dismissViewControllerAnimated:YES completion:^{}];

            ImagePickerController *sSelf = wSelf;
            if (sSelf.finishBlock) {
                sSelf.finishBlock(ImagePickerTypeScanQRCode,ImagePickerStatusSuccess,result);
            }
        }];
    }];

QRViewController是一个ViewController控制器,所以页面的启动可以根据需要用push还是用modal方式,上图实例中是采用的modal方式;startScanQRCodeWithFinish启动扫描,通过block的方式回调传回扫描的结果。

5)二维码图片识别和生成

是通过给UIImage做一个类别扩展,方法定义如下:

// 生成二维码
+ (UIImage *)generateQRCode:(NSString *)code width:(CGFloat)width height:(CGFloat)height;
// 二维码识别
- (NSArray *)recognitionQRCodeFromImage;

6)验证码控件类CaptchaControl

范例:

CaptchaControl *codeCtrl = [[CaptchaControl alloc] initWithFrame:CGRectMake(40, 100, 90, 30) interval:60];
    [codeCtrl setBackgroundColor:[UIColor lightTextColor]];
    [codeCtrl addTarget:self action:@selector(getCode:) forControlEvents:UIControlEventTouchUpInside];
    [codeCtrl setDefaultText:@"验证码"];
    [self.view addSubview:codeCtrl];

7)循环轮播控件CycleBannerView

范例:

CycleBannerView *banner = [[CycleBannerView alloc] initWithFrame:view.bounds];
    NSArray *images = @[@"http://pic22.nipic.com/20120717/9774499_115645635000_2.jpg",
                        @"http://pic4.nipic.com/20090919/3372381_123043464790_2.jpg",
                        @"http://www.9doo.net/__demo/jd0024/upload/b1.jpg",
                        @"http://pic.58pic.com/58pic/13/18/50/23K58PIC38v_1024.jpg",
                        @"http://pic2.ooopic.com/10/57/50/93b1OOOPIC4d.jpg"];
    [banner reloadData:images];
    [banner setPageControlPos:PageControlPositionRight];
    [banner autoScroll];
    [view addSubview:banner];

可设置pageControl的位置;也可设置是否是自动轮播,默认不自动轮播。

8)自消失的提示框控件FadePromptView

(1)范例-默认位置弹出

[FadePromptView showPromptStatus:@"当前设置暂时没有办法发送邮件" duration:1.0 finishBlock:nil];

(2)范例-指定位置弹出

[FadePromptView showPromptStatus:@"请输入您的笔记~" duration:0.6 positionY:[DeviceInfo screenHeight]- 300 finishBlock:^{
                //
            }];

上述两个范例都是可以支持提示框消失后的回调。

9)九宫格控件GridMenuView

self.gridView = [[GridMenuView alloc] initWithFrame:CGRectMake(0, [DeviceInfo navigationBarHeight], [DeviceInfo screenWidth], [DeviceInfo screenHeight] - [DeviceInfo navigationBarHeight])];
    [_gridView setDelegate:self];
    [_gridView setColumnCount:3];
    [_gridView setRowHeight:120];

    [self.view addSubview:_gridView];

    [_gridView appendingMenusData:[self gridData]];

- (NSArray *)gridData {

    GridMenuItem *item1 = [[GridMenuItem alloc] init];
    item1.icon = @"http://ico.58pic.com/iconset01/Doraemon-icons/gif/79802.gif";
    item1.title = @"菜单1";
    item1.iconSize = CGSizeMake(60, 60);
    item1.titleFont = [UIFont systemFontOfSize:14];
    item1.titleColor = [UIColor grayColor];

    GridMenuItem *item2 = [[GridMenuItem alloc] init];
    item2.icon = @"http://ico.58pic.com/iconset02/fast_icon_users/gif/13406.gif";
    item2.title = @"菜单2";
    item2.iconSize = CGSizeMake(60, 60);
    item2.titleFont = [UIFont systemFontOfSize:14];
    item2.titleColor = [UIColor grayColor];

    GridMenuItem *item3 = [[GridMenuItem alloc] init];
    item3.icon = @"http://ico.58pic.com/iconset01/Doraemon-icons/gif/79792.gif";
    item3.title = @"菜单3";
    item3.iconSize = CGSizeMake(60, 60);
    item3.titleFont = [UIFont systemFontOfSize:14];
    item3.titleColor = [UIColor grayColor];


    NSArray *menus = @[item1,item2,item3];
    return menus;
}

此九宫格布局,如下图所示:
这里写图片描述

10)icon菜单控件AIActionSheet

范例:

AIActionSheet *sheet = [[AIActionSheet alloc] initInParentView:self.tabBarController.view delegate:self];
        for (int i = 0; i < 7; i ++) {
            AISheetItem * item = [[AISheetItem alloc] init];
            item.icon = @"capture.png";
            item.title = [NSString stringWithFormat:@"测试测-%d",i];
            [sheet addActionItem:item];
        }
        [sheet show];

它所展示的效果如下:
这里写图片描述

11)图片视频选择器类ImagePickerController

这个类集成了图片的选择,系统的拍照、系统的录像、二维码识别等能力。使用简单请参考.h里的接口定义即可

12)邮件和短信发送器类MailSMSController

这个类集成了邮件和短信的发送,使用简单请参考.h里的接口定义即可。

13)HTTP通信及数据model一体化封装

通信引擎类NetworkTask,它封装了常用的http通信API:文件上传、GET、POST、PUT、DELETE等等,它需要结合数据model类配套使用。
数据model基类NetResultBase。

范例:

// 1、接口调用
NSDictionary* param =[[NSDictionary alloc] initWithObjectsAndKeys:
                              nameString,@"phone",
                              [pwdString md5EncodeUpper:NO],@"passwd",nil];
        [SVProgressHUD showWithStatus:@"正在登录..." maskType:SVProgressHUDMaskTypeBlack];
        [[NetworkTask sharedNetworkTask] startPOSTTaskApi:API_Login
                                                 forParam:param
                                                 delegate:self
                                                resultObj:[[LoginResult alloc] init]
                                               customInfo:@"login"];

// 2、回调实现
#pragma mark - NetworkTaskDelegate
-(void)netResultSuccessBack:(NetResultBase *)result forInfo:(id)customInfo {
    [SVProgressHUD dismiss];

    if ([customInfo isEqualToString:@"login"]) {
        AppDelegate *app = [AppDelegate shareMyApplication];
        [app.mainVC switchToHomeVC];

        LoginResult *userInfo = (LoginResult *)result;
        [[SysDataSaver SharedSaver] saveUserInfo:userInfo];
    }
}


-(void)netResultFailBack:(NSString *)errorDesc errorCode:(NSInteger)errorCode forInfo:(id)customInfo {
    [SVProgressHUD dismiss];
    [FadePromptView showPromptStatus:errorDesc duration:1.0 finishBlock:^{
        //
    }];
}

// 实现配套的数据model类
//
//  LoginResult.h
//
//  Created by wuyj on 16/12/14.
//  Copyright © 2016年 Asiainfo. All rights reserved.
//

#import "NetResultBase.h"

@interface LoginResult : NetResultBase<NSCoding>
@property (nonatomic, copy)NSString *nick;
@property (nonatomic, copy)NSString *avatar;
@property (nonatomic, copy)NSString *favorCount;
@property (nonatomic, copy)NSString *noteCount;
@property (nonatomic, copy)NSString *user_id;
@property (nonatomic, copy)NSString *phone;
@property (nonatomic, copy)NSString *mood;
@end

注意对于数据model对象,如果数据字段是Array类型,请使用宏定义定义,如下:

@property(nonatomic,strong,getter=arrayLeibie)NSArray        *BaiduParserArray(leibie,NSString);

上述宏定义:BaiduParserArray,里面有两个参数第一参数:leibie是Array字段名称;NSString是Array的item的类型;当然也可以使用自定义的类,如下:

@property(nonatomic,strong,getter=arrayBook)NSArray        *BaiduParserArray(books,BookItem);

上述Array字段名books,Array的item的类型:BookItem,定义如下:

@interface BookItem : NSObject
@property (nonatomic, copy)NSString *id;
@property (nonatomic, copy)NSString *name;
@property (nonatomic, copy)NSString *pic_big;
@property (nonatomic, copy)NSString *pic_small;
@property (nonatomic, copy)NSString *author;
@property (nonatomic, copy)NSString *range;
@property (nonatomic, copy)NSString *type;
@property (nonatomic, copy)NSString *f_age;
@property (nonatomic, copy)NSString *press;
@property (nonatomic, copy)NSString *isbn;
@property (nonatomic, copy)NSString *recommend;
@property (nonatomic, copy)NSString *link;
@property (nonatomic, copy)NSString *comment;
@property (nonatomic, copy)NSString *status;
@property (nonatomic, copy)NSString *created_date;
@property (nonatomic, copy)NSString *created;
@property (nonatomic, copy)NSString *isOnline;
@property (nonatomic, copy)NSString *isFavor;
@property (nonatomic, copy)NSString *price;

@property (nonatomic, copy)NSString *statement;
@property (nonatomic, copy)NSString *brief;
@property (nonatomic, copy)NSString *introduction;
@property (nonatomic, copy)NSString *pic_intr;
@property (nonatomic, copy)NSString *pic_jj;
@end

13)独立的分享框架

分享能力我们目前是提供一个独立的framework,目前集成了3个常用的分享平台: 微信、QQ、微博;
如果需要使用分享能力,请引入我们框架的AIShare.framework框架包。这个框架中主要实现了3大平台的分享能力,同时集成了支付能力。
主要提供的类如下图所示:

这里写图片描述

(1)SharedDataModel,分享的数据类;

(2)SharedManager,分享引擎类;

使用范例:

SharedDataModel *sharedData = [[SharedDataModel alloc] init];
        sharedData.content = @"测试URL分享";
        sharedData.title = @"测试视频分享";
        sharedData.url = @"http://www.tudou.com/programs/view/_cVM3aAp270/";
        sharedData.dataType = SharedDataTypeText;
        [[SharedManager sharedManager] sharedData:sharedData finish:^(NSInteger statusCode,id resp) {
            //
        }];

14)数据存储、处理集合

(1)keychain存储类:AISave2Keychain

(2)剪贴板存储类:AIPasteboard

(3)基于系统的UserDefault存储类:SysDataSaver

(4)文件存储类:FileCache

(5)文件流操作类:FileStreamOperation

(6)图片处理类别:UIImage+Utility和UIImage+ResizeMagick

(7)颜色处理类别:UIColor+Utility

(8)字符串处理类别:NSString+Utility

(9)数据流处理类别:NSData+Crypto

(10)zip解压缩:ZipArchiveEx

14)framework动态加载框架

这个框架主要是封装framework的动态加载和资源从framework的自己的bundle中加载的能力。这封装主要解决就是iOS平台实现插件机制。
主要掌握下面两个类的使用,请参考.h文件即可:

(1)AIPluginLoader类:framework插件加载器。

//
//  AIPluginLoader.h
//  CommonProject
//
//  Created by wuyoujian on 2017/6/19.
//
//

#import <Foundation/Foundation.h>
#import "../Owns/AINavigationController.h"
#import "../Owns/AICommonDef.h"
#import "AIPluginProtocol.h"


typedef NS_ENUM(NSInteger,PluginLoadStatus) {

    PluginLoadStatusNone = 0,
    PluginLoadStatusUnDownload = 1,     // 没有下载
    PluginLoadStatusDownloading = 2,    // 下载中
    PluginLoadStatusDownloaded = 3,     // 下载完毕
    PluginLoadStatusException = 4,      // 加载异常

};

@interface AIPluginLoader : NSObject

AISINGLETON_DEF(AIPluginLoader,SharedObj);

// 获取插件的状态
- (PluginLoadStatus)pluginloadStatus:(NSString*)pluginURL;

// 下载插件
- (void)downloadPlugin:(NSString*)pluginURL;

// 加载插件
- (void)loadPluginName:(NSString*)frameworkName
                   nav:(AINavigationController*)navVC
      enterVCClassName:(NSString*)className;

// 加载插件
- (UIViewController<AIPluginProtocol> *)loadPluginName:(NSString*)frameworkName enterVCClassName:(NSString*)className;

@end

(2)AIPluginTools:framework资源加载工具类

//
//  AIPluginTools.h
//  AIBase
//
//  Created by wuyoujian on 2017/6/21.
//  Copyright © 2017年 Asiainfo. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "../Owns/AICommonDef.h"

@interface AIPluginTools : NSObject

AISINGLETON_DEF(AIPluginTools,SharedObj);

// 从framework根目录下加载图片
- (UIImage *)roadImageWithName:(NSString *)name;

// 从framework根目录下的包名:@param bunleName 中加载图片,例如,res.bundle
- (UIImage *)roadImageWithName:(NSString *)name inResBundle:(NSString*)bundleName;

// 从矢量图加载图片
- (UIImage *)roadVectorImageWithName:(NSString *)name;

// 从framework根目录下加载其他资源
- (NSData *)roadResWithName:(NSString*)name;

// 从framework根目录下的包名:@param bunleName 中加载其他资源,例如,res.bundle
- (NSData *)roadResWithName:(NSString*)name inResBundle:(NSString *)bundleName;

// 返回资源路径
- (NSString *)resPathWithName:(NSString*)name;

// 返回资源路径
- (NSString *)resPathWithName:(NSString*)name inResBundle:(NSString *)bundleName;


@end

iOS平台的能力待续。。。

2、android平台提供的能力

目前android平台的能力提供仅满足crm常用的能力,后面陆续新增能力,在封装android能力的时候,我们是全部采用代码来实现控件,资源文件能实现编码的采用编码。

1)自定义证件拍照控件类RectCameraActivity

使用范例:

// 拍照
    @JavascriptInterface
    @NotProguard
    public void JN_Photograph(String functionName) {
        final String  mFunctionName = functionName;
        final String checkPermissinos [] = {Manifest.permission.CAMERA,
                Manifest.permission.WRITE_EXTERNAL_STORAGE};
        PermissionUitls.mContext = getActivity();
        if(!PermissionUitls.isGetAllPermissionsByList(checkPermissinos) ) {
            new AlertDialog
                    .Builder(getActivity())
                    .setTitle("提示信息")
                    .setMessage("该功能需要您接受应用对一些关键权限(拍照)的申请,如之前拒绝过,可到手机系统的应用管理授权设置界面再次设置。")
                    .setPositiveButton("确认", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            checkPermission(mFunctionName,PermissionUitls.PERMISSION_CAMERA_CODE,checkPermissinos);
                        }
                    }).show();
        } else {

            jumpToRectCameraActivity(functionName);
        }
    }

    private void jumpToRectCameraActivity(String functionName) {
        Intent intent = new Intent(getActivity(), RectCameraActivity.class);
        intent.putExtra("functionName",functionName);
        intent.putExtra("fileId","fileId");
        getActivity().startActivityForResult(intent, 101);
    }

2)手写控件类AISignatureView

它是一个标准的View类,可以类似于系统的View一样的使用方式;他提供保存手写图片、获取手写图片的Bitmap对象、删除保存的图片、设置笔的粗细、设置画布背景、设置画笔颜色等等能力;

3)手势密码控件类AIGesturePasswordLayout

它是一个标准的View类,用法同系统的View,下面我们给一份使用纯代码布局的范例:

mGesturePasswordLayout = new AIGesturePasswordLayout(this);
        mGesturePasswordLayout.setGravity(Gravity.CENTER_VERTICAL);
        mGesturePasswordLayout.setBackgroundColor(0x00ffffff);
        mGesturePasswordLayout.setOnGestureLockViewListener(mListener);

        //
        tvParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
                RelativeLayout.LayoutParams.MATCH_PARENT);
        mRelativeLayout.addView(mGesturePasswordLayout,tvParams);

4)扫码控件类CaptureActivity

这个控件是基于ZXing开源库来封装的。
使用范例:

private void ToScanCode2(int type) {
        //跳转扫描页面
        Intent intent = new Intent(getActivity(), CaptureActivity.class);
        intent.putExtra("type",type);
        getActivity().startActivityForResult(intent,SCAN_BAR_CODE_REQUEST_CODE);
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章