weex android 组件,Weex系列(5) —— 封装原生组件和模块

目录

哇,2019年了,时间总是那么快,快过新年了,忙点了也懒点了,还有点想家了,先祝大家新年快乐吧。

这一章官网上有介绍,但还是单独拎出来讲一讲,因为后期这块用的还是挺多的。

官网的所有组件和模块的截图:

bVbmR68?w=758&h=1274

在官网 扩展版块,是可以找到封装的方法步骤的。

自定义模块

iOS:

第一步:

新建 myModule.h

#import

#import

@interface myModule : NSObject

@end

新建 myModule.m

#import "myModule.h"

@implementation myModule

WX_EXPORT_METHOD(@selector(log:))

- (void)log:(NSString *)inputParam

{

NSLog(@"%@",inputParam);

}

@end

第二步:

AppDelegate.m里面注册module

[WXSDKEngine registerModule:@"myModule" withClass:[myModule class]];

Android:

第一步:

新建myModule.java

public class MyModule extends WXModule {

//run JS thread

@JSMethod (uiThread = false)

public void log(String inputParam) {

Log.d("自定义模块:", inputParam);

}

}

第二步:

WXApplication.java里面注册module

WXSDKEngine.registerModule("MyModule", MyModule.class);

最后:

在上层vue里面,我们可以require我们自己封装的module,就能够调用原生的log方法,分别在xcode和Android Studio的控制台,看到hello weex的消息了。

这里需要强调一点的是:iOS和Android的module的名字方法要一致,这样在vue里面才能统一的。

weex.requireModule("myModule").log("hello weex")

自定义组件

组件封装起来比模块是麻烦许多的,一开始也是摸不着头脑,后来就找到weexsdk里面封装的组件,依样画葫芦的开始了。

bVbmThj?w=1138&h=572

iOS:

第一步:

新建myComponent.h

#import "WXComponent.h"

@interface myComponent : WXComponent

- (void)notifyWebview:(NSDictionary *) data;

- (void)reload;

- (void)goBack;

- (void)goForward;

@end

新建myComponent.m

#import "myComponent.h"

#import

#import

#import "WXUtility.h"

#import "WXURLRewriteProtocol.h"

#import "WXSDKEngine.h"

#import

@interface WXWebView : UIWebView

@end

@implementation WXWebView

- (void)dealloc

{

if (self) {

// self.delegate = nil;

}

}

@end

@interface myComponent ()

@property (nonatomic, strong) JSContext *jsContext;

@property (nonatomic, strong) WXWebView *webview;

@property (nonatomic, strong) NSString *url;

@property (nonatomic, assign) BOOL startLoadEvent;

@property (nonatomic, assign) BOOL finishLoadEvent;

@property (nonatomic, assign) BOOL failLoadEvent;

@property (nonatomic, assign) BOOL notifyEvent;

@end

@implementation myComponent

WX_EXPORT_METHOD(@selector(goBack))

WX_EXPORT_METHOD(@selector(reload))

WX_EXPORT_METHOD(@selector(goForward))

- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance

{

if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {

self.url = attributes[@"src"];

}

return self;

}

- (UIView *)loadView

{

return [[WXWebView alloc] init];

}

- (void)viewDidLoad

{

_webview = (WXWebView *)self.view;

_webview.delegate = self;

_webview.allowsInlineMediaPlayback = YES;

_webview.scalesPageToFit = YES;

[_webview setBackgroundColor:[UIColor clearColor]];

_webview.opaque = NO;

_jsContext = [_webview valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

__weak typeof(self) weakSelf = self;

_jsContext[@"$notifyWeex"] = ^(JSValue *data) {

if (weakSelf.notifyEvent) {

[weakSelf fireEvent:@"notify" params:[data toDictionary]];

}

};

if (_url) {

[self loadURL:_url];

}

}

- (void)updateAttributes:(NSDictionary *)attributes

{

if (attributes[@"src"]) {

self.url = attributes[@"src"];

}

}

- (void)addEvent:(NSString *)eventName

{

if ([eventName isEqualToString:@"pagestart"]) {

_startLoadEvent = YES;

}

else if ([eventName isEqualToString:@"pagefinish"]) {

_finishLoadEvent = YES;

}

else if ([eventName isEqualToString:@"error"]) {

_failLoadEvent = YES;

}

}

- (void)setUrl:(NSString *)url

{

NSString* newURL = [url copy];

WX_REWRITE_URL(url, WXResourceTypeLink, self.weexInstance)

if (!newURL) {

return;

}

if (![newURL isEqualToString:_url]) {

_url = newURL;

if (_url) {

[self loadURL:_url];

}

}

}

- (void)loadURL:(NSString *)url

{

if (self.webview) {

NSURLRequest *request =[NSURLRequest requestWithURL:[NSURL URLWithString:url]];

[self.webview loadRequest:request];

}

}

- (void)reload

{

[self.webview reload];

}

- (void)goBack

{

if ([self.webview canGoBack]) {

[self.webview goBack];

}

}

- (void)goForward

{

if ([self.webview canGoForward]) {

[self.webview goForward];

}

}

- (void)notifyWebview:(NSDictionary *) data

{

NSString *json = [WXUtility JSONString:data];

NSString *code = [NSString stringWithFormat:@"(function(){var evt=null;var data=%@;if(typeof CustomEvent==='function'){evt=new CustomEvent('notify',{detail:data})}else{evt=document.createEvent('CustomEvent');evt.initCustomEvent('notify',true,true,data)}document.dispatchEvent(evt)}())", json];

[_jsContext evaluateScript:code];

}

#pragma mark Webview Delegate

- (NSMutableDictionary *)baseInfo

{

NSMutableDictionary *info = [NSMutableDictionary new];

[info setObject:self.webview.request.URL.absoluteString ?: @"" forKey:@"url"];

[info setObject:[self.webview stringByEvaluatingJavaScriptFromString:@"document.title"] ?: @"" forKey:@"title"];

[info setObject:@(self.webview.canGoBack) forKey:@"canGoBack"];

[info setObject:@(self.webview.canGoForward) forKey:@"canGoForward"];

return info;

}

- (void)webViewDidStartLoad:(UIWebView *)webView

{

}

- (void)webViewDidFinishLoad:(UIWebView *)webView

{

if (_finishLoadEvent) {

NSDictionary *data = [self baseInfo];

[self fireEvent:@"pagefinish" params:data domChanges:@{@"attrs": @{@"src":self.webview.request.URL.absoluteString}}];

}

}

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error

{

if (_failLoadEvent) {

NSMutableDictionary *data = [self baseInfo];

[data setObject:[error localizedDescription] forKey:@"errorMsg"];

[data setObject:[NSString stringWithFormat:@"%ld", (long)error.code] forKey:@"errorCode"];

NSString * urlString = error.userInfo[NSURLErrorFailingURLStringErrorKey];

if (urlString) {

// webview.request may not be the real error URL, must get from error.userInfo

[data setObject:urlString forKey:@"url"];

if (![urlString hasPrefix:@"http"]) {

return;

}

}

[self fireEvent:@"error" params:data];

}

}

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType

{

if (_startLoadEvent) {

NSMutableDictionary *data = [NSMutableDictionary new];

[data setObject:request.URL.absoluteString ?:@"" forKey:@"url"];

[self fireEvent:@"pagestart" params:data];

}

return YES;

}

@end

第二步:

AppDelegate.m里面注册component

[WXSDKEngine registerComponent:@"myComponent" withClass:[myComponent class]];

这里需要说明:上面基本上是照着weexsdk里面的webview组件改的,而且就是改了一下名字,方法什么的大家就可以自由发挥了。

Android:

第一步:

新建myComponent.java

/*

* Licensed to the Apache Software Foundation (ASF) under one

* or more contributor license agreements. See the NOTICE file

* distributed with this work for additional information

* regarding copyright ownership. The ASF licenses this file

* to you under the Apache License, Version 2.0 (the

* "License"); you may not use this file except in compliance

* with the License. You may obtain a copy of the License at

*

* http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing,

* software distributed under the License is distributed on an

* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

* KIND, either express or implied. See the License for the

* specific language governing permissions and limitations

* under the License.

*/

package com.taobao.weex.ui.component;

import android.content.Context;

import android.net.Uri;

import android.support.annotation.NonNull;

import android.text.TextUtils;

import android.view.View;

import com.taobao.weex.WXSDKInstance;

import com.taobao.weex.annotation.Component;

import com.taobao.weex.adapter.URIAdapter;

import com.taobao.weex.common.Constants;

import com.taobao.weex.dom.WXDomObject;

import com.taobao.weex.ui.view.IWebView;

import com.taobao.weex.ui.view.WXWebView;

import com.taobao.weex.utils.WXUtils;

import java.util.HashMap;

import java.util.Map;

@Component(lazyload = false)

public class myComponent extends WXComponent {

public static final String GO_BACK = "goBack";

public static final String GO_FORWARD = "goForward";

public static final String RELOAD = "reload";

protected IWebView mWebView;

@Deprecated

public myComponent(WXSDKInstance instance, WXDomObject dom, WXVContainer parent, String instanceId, boolean isLazy) {

this(instance,dom,parent,isLazy);

}

public myComponent(WXSDKInstance instance, WXDomObject dom, WXVContainer parent, boolean isLazy) {

super(instance, dom, parent, isLazy);

createWebView();

}

protected void createWebView(){

mWebView = new WXWebView(getContext());

}

@Override

protected View initComponentHostView(@NonNull Context context) {

mWebView.setOnErrorListener(new IWebView.OnErrorListener() {

@Override

public void onError(String type, Object message) {

fireEvent(type, message);

}

});

mWebView.setOnPageListener(new IWebView.OnPageListener() {

@Override

public void onReceivedTitle(String title) {

if (getDomObject().getEvents().contains(Constants.Event.RECEIVEDTITLE)) {

Map params = new HashMap<>();

params.put("title", title);

fireEvent(Constants.Event.RECEIVEDTITLE, params);

}

}

@Override

public void onPageStart(String url) {

if ( getDomObject().getEvents().contains(Constants.Event.PAGESTART)) {

Map params = new HashMap<>();

params.put("url", url);

fireEvent(Constants.Event.PAGESTART, params);

}

}

@Override

public void onPageFinish(String url, boolean canGoBack, boolean canGoForward) {

if ( getDomObject().getEvents().contains(Constants.Event.PAGEFINISH)) {

Map params = new HashMap<>();

params.put("url", url);

params.put("canGoBack", canGoBack);

params.put("canGoForward", canGoForward);

fireEvent(Constants.Event.PAGEFINISH, params);

}

}

});

return mWebView.getView();

}

@Override

public void destroy() {

super.destroy();

getWebView().destroy();

}

@Override

protected boolean setProperty(String key, Object param) {

switch (key) {

case Constants.Name.SHOW_LOADING:

Boolean result = WXUtils.getBoolean(param,null);

if (result != null)

setShowLoading(result);

return true;

case Constants.Name.SRC:

String src = WXUtils.getString(param,null);

if (src != null)

setUrl(src);

return true;

}

return super.setProperty(key,param);

}

@WXComponentProp(name = Constants.Name.SHOW_LOADING)

public void setShowLoading(boolean showLoading) {

getWebView().setShowLoading(showLoading);

}

@WXComponentProp(name = Constants.Name.SRC)

public void setUrl(String url) {

if (TextUtils.isEmpty(url) || getHostView() == null) {

return;

}

if (!TextUtils.isEmpty(url)) {

loadUrl(getInstance().rewriteUri(Uri.parse(url), URIAdapter.WEB).toString());

}

}

public void setAction(String action) {

if (!TextUtils.isEmpty(action)) {

if (action.equals(GO_BACK)) {

goBack();

} else if (action.equals(GO_FORWARD)) {

goForward();

} else if (action.equals(RELOAD)) {

reload();

}

}

}

private void fireEvent(String type, Object message) {

if (getDomObject().getEvents().contains(Constants.Event.ERROR)) {

Map params = new HashMap<>();

params.put("type", type);

params.put("errorMsg", message);

fireEvent(Constants.Event.ERROR, params);

}

}

private void loadUrl(String url) {

getWebView().loadUrl(url);

}

private void reload() {

getWebView().reload();

}

private void goForward() {

getWebView().goForward();

}

private void goBack() {

getWebView().goBack();

}

private IWebView getWebView() {

return mWebView;

}

}

第二步:

WXApplication.java里面注册component

WXSDKEngine.registerComponent("myComponent", myComponent.class);

最后:

在上层vue里面,我们就可以直接使用封装好的组件。

这里需要强调一点的是:iOS和Android的组件名字一定要一致,这样在vue里面才能统一的。

小结

1、从上面可以看出不管是组件还是模块,都是要iOS和Android各封装一套的,而且名字还要一致,如果兼容web端,还要做web的扩展,这样才能三端统一的。

2、封装组件的版块,我把weex sdk里面的web组件代码拿出来了,也是为了后面webview章节做铺垫吧。

3、建议大家可以多看看weex sdk的源码,(这里请忘掉我只是一个前端,我干嘛还要学习oc、java的这些想法吧)其实也还好,也可能是目前我们的项目没有太复杂,封装的还不是很多,也还算简单,谷歌上一搜基本都能解决吧。

最后祝大家新的一年,少点bug,多点money,越来越好吧。

如果喜欢就请点个赞收藏一下啦~~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值