2016-06-11 14:57:08 su_sai 阅读数 4464
  • 微服务和云原生架构实践

    通过剖析和展示一个端到端的简化微服务应用案例MovieApp,帮助学员学习理解现代微服务应用和云原生架构实践,内容包括: * 微服务应用架构 * 前后分离应用架构 * 基于Spring Security + JWT的微服务安全架构 * Spring Boot微服务应用开发和测试 * 基于React的前端应用开发 * Spring Cloud Gateway在微服务架构中的应用 * Docker Compose镜像构建和本地应用部署 * Kubernetes核心概念和应用部署 同时帮助学员熟悉现代应用开发技术栈, 包括: * Spring Boot ~ 开发框架 * Spring Security ~ 安全框架 * MyBatis ~ ORM框架 * JWT ~ 令牌框架 * React ~ 前端框架 * MySQL ~ 后端存储 * Spring Cloud Gateway ~ 微服务网关 * Zipkin ~ 调用链监控 * Docker Compose ~ 镜像构建和本地部署 * Kubernetes ~ 容器调度和部署 项目源码:https://github.com/jskillcloud/MovieApp

    4987 人正在学习 去看看 杨波

JS 通过native.js可以调用Android原生API。下面具体介绍使用JS调用Android的AlertDialog创建一个信息窗口。


1.android Java程序

import android.app.AlertDialog;
//...
// 创建提示框构造对象,Builder是AlertDialog的内部类。参数this指代Android的主Activity对象,该对象启动应用时自动生成
AlertDialog.Builder dlg = new AlertDialog.Builder(this);
// 设置提示框标题
dlg.setTitle("自定义标题");
// 设置提示框内容
dlg.setMessage("使用NJS的原生弹出框,可自定义弹出框的标题、按钮");
// 设置提示框按钮
dlg.setPositiveButton("确定(或者其他字符)", null);
// 显示提示框
dlg.show();
//...


2. HBuilder环境编写JS程序

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Barcode Example</title>
<script type="text/javascript" >
document.addEventListener( "plusready", ready,false);
function ready()
{}
function sms()
{
var alertdialog = plus.android.importClass("android.app.AlertDialog")
var dlg = new alertdialog.Builder(plus.android.runtimeMainActivity())
dlg.setTitle("自定义标题")
dlg.setMessage("使用NJS的原生弹出框,可自定义弹出框的标题、按钮")
dlg.setPositiveButton("确定(或者其他字符)",null)
dlg.show()
}
</script>
</head>
<body >
<button onclick="sms()">sms</button>
</body>
</html>



2017-06-12 23:23:09 u011272795 阅读数 2427
  • 微服务和云原生架构实践

    通过剖析和展示一个端到端的简化微服务应用案例MovieApp,帮助学员学习理解现代微服务应用和云原生架构实践,内容包括: * 微服务应用架构 * 前后分离应用架构 * 基于Spring Security + JWT的微服务安全架构 * Spring Boot微服务应用开发和测试 * 基于React的前端应用开发 * Spring Cloud Gateway在微服务架构中的应用 * Docker Compose镜像构建和本地应用部署 * Kubernetes核心概念和应用部署 同时帮助学员熟悉现代应用开发技术栈, 包括: * Spring Boot ~ 开发框架 * Spring Security ~ 安全框架 * MyBatis ~ ORM框架 * JWT ~ 令牌框架 * React ~ 前端框架 * MySQL ~ 后端存储 * Spring Cloud Gateway ~ 微服务网关 * Zipkin ~ 调用链监控 * Docker Compose ~ 镜像构建和本地部署 * Kubernetes ~ 容器调度和部署 项目源码:https://github.com/jskillcloud/MovieApp

    4987 人正在学习 去看看 杨波

今天学习了一下在react-native中调用原生安卓模块的使用,发现很多网上的文章都是直接照抄的文档,这样会有一些坑,导致最后无法运行或者成功调用,所以写下这个博客来分享,同时也记录一下学习过程,内容完整,浅显易懂,仔细看下来肯定会学会的。

学习理由:

有时候App需要访问平台API,但React Native可能还没有相应的模块包装;或者你需要复用一些Java代码,而不是用Javascript重新实现一遍;又或者你需要实现某些高性能的、多线程的代码,譬如图片处理、数据库、或者各种高级扩展等等。


我们把React Native设计为可以在其基础上编写真正的原生代码,并且可以访问平台所有的能力。这是一个相对高级的特性,我们并不认为它应当在日常开发的过程中经常出现,但具备这样的能力是很重要的。如果React Native还不支持某个你需要的原生特性,你应当可以自己实现该特性的封装。

本向导会用Toast作为例子。假设我们希望可以从Javascript发起一个Toast消息(Android中的一种会在屏幕下方弹出、保持一段时间的消息通知)
我们首先来创建一个原生模块。一个原生模块是一个继承了ReactContextBaseJavaModule的Java类,它可以实现一些JavaScript所需的功能。我们这里的目标是可以在JavaScript里写ToastAndroid.show('Awesome', ToastAndroid.SHORT);,来调起一个Toast通知。


先看一下我的目录:


1. 首先,我们创建一个java类 MyToast:

这个类一定要继承自 ReactContextBaseJavaModule ,

public class MyToast extends ReactContextBaseJavaModule {

    private static final String DURATION_SHORT_KEY = "SHORT";
    private static final String DURATION_LONG_KEY = "LONG";

    public MyToast(ReactApplicationContext reactContext) {
        super(reactContext);
    }

    /**
     * 一个可选的方法getContants返回了需要导出给JavaScript使用的常量。
     * 它并不一定需要实现,但在定义一些可以被JavaScript同步访问到的预定义的值时非常有用。
     */
    @Nullable
    @Override
    public Map<String, Object> getConstants() {
        final Map<String, Object> constants = new HashMap();
        constants.put(DURATION_LONG_KEY, Toast.LENGTH_LONG);
        constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT);

        return constants;
    }

    /**
     * 要导出一个方法给JavaScript使用,Java方法需要使用注解@ReactMethod     * 方法的返回类型必须为voidReact Native的跨语言访问是异步进行的,
     * 所以想要给JavaScript返回一个值的唯一办法是使用回调函数或者发送事件
     * @param message
     * @param duration
     */
    @ReactMethod
    public void show(String message, int duration) {
        Toast.makeText(getReactApplicationContext(), message, duration).show();
    }

    /**
     * 模块名前的RCT前缀会被自动移除。
     * 所以如果返回的字符串为"RCTmytoast",在JavaScript端依然可以通过React.NativeModules.mytoast访问到这个模块。
     * @return
     */
    @Override
    public String getName() {
        return "mytoast";
    }
}

ReactContextBaseJavaModule要求派生类实现getName方法。这个函数用于返回一个字符串名字,这个名字在JavaScript端标记这个模块。这里我们把这个模块叫做mytoast,这样就可以在JavaScript中通过React.NativeModules.mytoast访问到这个模块

注意,文档上写的是ToastAndroid,但是RN已经内置了一个名为ToastAndroid的模块,所以如果你在练习时完全照抄,那么运行时会报错名字冲突!所以我在这里选择了另外一个名字:mytoast 。


@Override
  public String getName() {
    return "mytoast";
  }
注意 :模块名前的RCT前缀会被自动移除。所以如果返回的字符串为"RCTmytoast",在JavaScript端依然可以通过React.NativeModules.mytoast访问到这个模块。

参数类型


下面的参数类型在@ReactMethod注明的方法中,会被直接映射到它们对应的JavaScript类型(例如上面的show方法,它被标明了@ReactMethod,所以它的参数会映射成下面这样)

Boolean -> Bool
Integer -> Number
Double -> Number
Float -> Number
String -> String
Callback -> function
ReadableMap -> Object
ReadableArray -> Array


上面方法中的参数( String message, int duration) 在javascript中就会转变成String和Number类型。


2.注册模块

在Java这边要做的最后一件事就是注册这个模块。我们需要在应用的Package类的createNativeModules方法中添加这个模块。如果模块没有被注册,它也无法在JavaScript中被访问到。

创建一个类,这个类要实现ReactPackage接口:

/**
 * Created by zhuoy on 2017/6/12.
 */

public class MyExampleToast implements ReactPackage {

    /**
     * 需要在应用的Package类的createNativeModules方法中添加这个模块。
     * 如果模块没有被注册,它也无法在JavaScript中被访问到。
     * @param reactContext
     * @return
     */
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {

        List<NativeModule> modules = new ArrayList<>();
        modules.add(new MyToast(reactContext));
        return modules;
    }

    @Override
    public List<Class<? extends JavaScriptModule>> createJSModules() {
        return Collections.emptyList();
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}

这个package需要在MainApplication.java文件的getPackages方法中提供。这个文件位于你的react-native应用文件夹的android目录中。具体路径是: android/app/src/main/java/com/your-app-name/MainApplication.java.

public class MainApplication extends Application implements ReactApplication {

    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
        @Override
        public boolean getUseDeveloperSupport() {
            return BuildConfig.DEBUG;
        }

        @Override
        protected List<ReactPackage> getPackages() {
            return Arrays.<ReactPackage>asList(
                    new MainReactPackage(),
                    new MyExampleToast()         //我们添加的方法
            );
        }

    };

    @Override
    public ReactNativeHost getReactNativeHost() {
        return mReactNativeHost;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        SoLoader.init(this, /* native exopackage */ false);
    }
}

在getPackages中添加我们刚刚写的package。


3.封装模块

为了让你的功能从JavaScript端访问起来更为方便,通常我们都会把原生模块封装成一个JavaScript模块。这不是必须的,但省下了每次都从NativeModules中获取对应模块的步骤。这个JS文件也可以用于添加一些其他JavaScript端实现的功能。

创建一个名为MyToast的js文件,注意创建文件的位置:


/**
 * Created by zhuoy on 2017/6/12.
 */
'use strict'
import {NativeModules} from 'react-native';
export default NativeModules.mytoast;

这里的mytoast就是我们之前写java文件中返回的字符串。

4.使用


import MyToast from './MyToast';

render() {
   
    return (
        <View>
           
            <Text onPress={() => MyToast.show('卓原',MyToast.SHORT)}>弹出Toast</Text>

        </View>
    )
}

如果不执行第三部的封装,想使用的话请这样写:

记得要先引入NativeModules:

import {
    其他需要用的组件,
    NativeModules
} from 'react-native';

<Text onPress={() => NativeModules.mytoast.show('卓原',
NativeModules.mytoast.SHORT)}>弹出Toast</Text>

可以看到,这样写代码稍显复杂,所以推荐封装一下再使用。


OK,大功告成。


2017-07-03 22:41:29 xiangzhihong8 阅读数 3771
  • 微服务和云原生架构实践

    通过剖析和展示一个端到端的简化微服务应用案例MovieApp,帮助学员学习理解现代微服务应用和云原生架构实践,内容包括: * 微服务应用架构 * 前后分离应用架构 * 基于Spring Security + JWT的微服务安全架构 * Spring Boot微服务应用开发和测试 * 基于React的前端应用开发 * Spring Cloud Gateway在微服务架构中的应用 * Docker Compose镜像构建和本地应用部署 * Kubernetes核心概念和应用部署 同时帮助学员熟悉现代应用开发技术栈, 包括: * Spring Boot ~ 开发框架 * Spring Security ~ 安全框架 * MyBatis ~ ORM框架 * JWT ~ 令牌框架 * React ~ 前端框架 * MySQL ~ 后端存储 * Spring Cloud Gateway ~ 微服务网关 * Zipkin ~ 调用链监控 * Docker Compose ~ 镜像构建和本地部署 * Kubernetes ~ 容器调度和部署 项目源码:https://github.com/jskillcloud/MovieApp

    4987 人正在学习 去看看 杨波

在React Native开发过程中,有时候我们可能需要访问平台的API,但react Native还没有相应的实现,或者是React Native还不支持一些原生的属性,我们需要调用原生代码来实现,或者是我们需要复用一些原来的Java代码,这个时候我们就需要创建一个原生模块来自己实现对我们需要功能的封装。 相关文档可以参照官方的介绍。

实例

下面我们就通过实现一个自定义模块,来熟悉编写原生模块需要用的一些知识。该模块主要实现调用一些Android原生的功能,比如弹Toast,启动Activity等。

实现模块

首先来创建一个原生模块。一个原生模块是一个继承了 ReactContextBaseJavaModule 的Java类,它有一个必须实现的方法getName(),它返回一个字符串名字,在js中我们就使用这个名字调用这个模块;还有构造函数NativeModule。

public class MyNativeModule extends ReactContextBaseJavaModule {
    private final static String MODULE_NAME = "MyNativeModule";
    private static final  String TestEvent = "TestEvent";
    private ReactApplicationContext mContext;
    public MyNativeModule(ReactApplicationContext reactContext) {
        super(reactContext);
        mContext = reactContext;
    }

    @Override
    public String getName() {
        return MODULE_NAME;
    }

    @Nullable
    @Override
    public Map<String, Object> getConstants() {
        final Map<String, Object> constants = new HashMap<>();
        constants.put("SHORT", Toast.LENGTH_SHORT);
        constants.put("LONG", Toast.LENGTH_LONG);
        constants.put("NATIVE_MODULE_NAME", MODULE_NAME);
        constants.put(TestEvent, TestEvent);
        return constants;
    }

    @ReactMethod
    public void startActivity(){
        Intent intent = new Intent(mContext,SecondActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        mContext.startActivity(intent);
    }

    @ReactMethod
    public void showToast(String msg, int duration){
        Toast.makeText(mContext, msg, duration).show();
    }
}

这里需要对React Native和原生的类型映射做一个简单的介绍。详细的还可以参考ReadableMapReadableArray

Boolean -> Bool
Integer -> Number
Double -> Number
Float -> Number
String -> String
Callback -> function
ReadableMap -> Object
ReadableArray -> Array

例如,实现getContants方法导出需要给JavaScript使用的常量。

@Nullable
    @Override
    public Map<String, Object> getConstants() {
        final Map<String, Object> constants = new HashMap<>();
        constants.put("SHORT", Toast.LENGTH_SHORT);
        constants.put("LONG", Toast.LENGTH_LONG);
        constants.put("NATIVE_MODULE_NAME", MODULE_NAME);
        constants.put(TestEvent, TestEvent);
        return constants;
    }

注册模块

接下来我们需要向系统注册这个模块,通过实现ReactPackage接口来实现。代码如下:

public class MyReactPackage implements ReactPackage {
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new MyNativeModule(reactContext));
        return modules;
    }

    @Override
    public List<Class<? extends JavaScriptModule>> createJSModules() {
        return Collections.emptyList();
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}

添加模块

在Application的getPackages()方法中添加上面的模块。

 @Override
        protected List<ReactPackage> getPackages() {
            return Arrays.<ReactPackage>asList(
                    new MainReactPackage(), 
                    //添加的模块
                    new MyReactPackage()
            );
        }

或者这MainActivity的onCreate中,添加如下代码:

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mReactRootView = new ReactRootView(this);
        mReactInstanceManager = ReactInstanceManager.builder()
                .setApplication(getApplication())
                .setBundleAssetName("index.android.bundle")
                .setJSMainModuleName("index.android")
                .addPackage(new MainReactPackage())
                .addPackage(new MyReactPackage())
                .setUseDeveloperSupport(BuildConfig.DEBUG)
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .build();
        mReactRootView.startReactApplication(mReactInstanceManager, "HelloWorld", null);
        setContentView(mReactRootView);
    }

Js端封装模块

为了使javascript端访问起来更为方便,通常我们都会把原生模块封装成一个JavaScript模块。

import { NativeModules } from 'react-native'; 

// 这里的MyNativeModule必须对应
// public String getName()中返回的字符串

export default NativeModules.MyNativeModule;

接下来,就可以直接使用了。

import MyNativeModule from './MyNativeModule'; 
class HelloWorld extends React.Component {
  startActivity(){
    console.log("MODULE NAME: ",MyNativeModule.NATIVE_MODULE_NAME);
    MyNativeModule.startActivity();
  }
  showToast(){
    console.log("MODULE NAME: ",MyNativeModule.NATIVE_MODULE_NAME);
    MyNativeModule.showToast("From JS", MyNativeModule.LONG);
  }
  render() {
    return (
      <View style={styles.container}>
        <TouchableOpacity onPress={this.startActivity}>  
          <Text style={styles.hello}>start Activity</Text>  
        </TouchableOpacity>
      </View>
    )
  }
}

其他知识

React Native的跨语言访问是异步进行的,所以想要给JavaScript返回一个值的唯一办法是使用回调函数或者发送事件。

回调函数

原生模块还支持一种特殊的参数——回调函数。它提供了一个函数来把返回值传回给JS。

@ReactMethod
    public void testCallback(int para1, int para2, Callback resultCallback){
        int result = para1 + para2;
        resultCallback.invoke(result);
    }

也可以在JS中调用。例如:

testCallback(){
    MyNativeModule.testCallback(100,100,(result) => {
    console.log("result: ",result); //'result: ', 200
    });
  }

原生模块通常只应调用回调函数一次。但是,它可以保存callback并在将来调用。
callback并非在对应的原生函数返回后立即被执行——注意跨语言通讯是异步的,这个执行过程会通过消息循环来进行。

RCTDeviceEventEmitter

生模块可以在没有被调用的情况下往JavaScript发送事件通知。最简单的办法就是通过RCTDeviceEventEmitter,这可以通过ReactContext来获得对应的引用。RCTDeviceEventEmitter相当于客户端的广播机制。

public void sendEvent(){
        WritableMap params = Arguments.createMap();
        params.putString("module", "MyNativeModule");
        mContext
                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit(TestEvent, params);
    }

在JS中调用的代码如下:

import { DeviceEventEmitter } from 'react-native';
......
  componentWillMount() {
    console.log("componentWillMount");
    //接收事件
    DeviceEventEmitter.addListener(MyNativeModule.TestEvent, info => {
      console.log(info);
    });
  }

startActivityForResult

如果需要监听activity的生命周期事件(比如onResume, onPause等等),模块必须实现LifecycleEventListener,然后需要在构造函数中注册一个监听函数。

public MyNativeModule(ReactApplicationContext reactContext) {
        super(reactContext);
        mContext = reactContext;
        //添加监听
        reactContext.addLifecycleEventListener(this);
    }

实现LifecycleEventListener的几个接口。

@Override
    public void onHostResume() {
        Log.e(MODULE_NAME, "onHostResume");
    }

    @Override
    public void onHostPause() {
        Log.e(MODULE_NAME, "onHostPause");
    }

    @Override
    public void onHostDestroy() {
        Log.e(MODULE_NAME, "onHostDestroy");
    }
2018-07-03 16:13:40 qq_23575795 阅读数 1473
  • 微服务和云原生架构实践

    通过剖析和展示一个端到端的简化微服务应用案例MovieApp,帮助学员学习理解现代微服务应用和云原生架构实践,内容包括: * 微服务应用架构 * 前后分离应用架构 * 基于Spring Security + JWT的微服务安全架构 * Spring Boot微服务应用开发和测试 * 基于React的前端应用开发 * Spring Cloud Gateway在微服务架构中的应用 * Docker Compose镜像构建和本地应用部署 * Kubernetes核心概念和应用部署 同时帮助学员熟悉现代应用开发技术栈, 包括: * Spring Boot ~ 开发框架 * Spring Security ~ 安全框架 * MyBatis ~ ORM框架 * JWT ~ 令牌框架 * React ~ 前端框架 * MySQL ~ 后端存储 * Spring Cloud Gateway ~ 微服务网关 * Zipkin ~ 调用链监控 * Docker Compose ~ 镜像构建和本地部署 * Kubernetes ~ 容器调度和部署 项目源码:https://github.com/jskillcloud/MovieApp

    4987 人正在学习 去看看 杨波

准备工作:具体详情参考React-Native官方文档

IDE: WebStorm 和Android Studio(webstorm不支持java高亮,所以用AS辅助下)

demo放到github上了,有需要的可以参考一下.  下载demo

1.为什么调用原生的一些东西? 

   有时候应用程序需要访问平台API,React Native目前还没有相应的模块。也许你想重用一些现有的Java代码,而不必用JavaScript重新实现它,或者编写一些高性能,多线程的代码,例如图像处理,数据库或任何数量的高级扩展。

我们设计了React Native,因此您可以编写真实的本机代码并访问平台的全部功能。这是一个更高级的功能,我们不希望它成为通常开发过程的一部分,但它存在必不可少。如果React Native不支持您需要的本机功能,您应该能够自己构建它。

2.创建个Toast模块做为示例:

 

我们首先创建一个本地模块。本地模块是一个Java类,通常扩展ReactContextBaseJavaModule该类并实现JavaScript所需的功能。我们的目标是能够使用ToastExample.show('Awesome', ToastExample.SHORT);JavaScript 编写在屏幕上显示简短toast。

2.1:创建一个名为ToastModule.java,其内容如下:

 

import android.widget.Toast;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

import java.util.HashMap;
import java.util.Map;

import javax.annotation.Nullable;

/**
 * Description:
 * Created by song on 2018/7/3.
 * email:bjay20080613@qq.com
 */
public class ToastModule  extends ReactContextBaseJavaModule {
    private static final String DURATION_SHORT_KEY="SHORT";
    private static final String DURATION_LONG_KEY="LONG";
    public ToastModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }

    @Override
    public String getName() {
        return "ToastExample";
    }

    @Nullable
    @Override
    public Map<String, Object> getConstants() {
        final Map<String,Object> constants=new HashMap<>();
        constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT);
        constants.put(DURATION_LONG_KEY,Toast.LENGTH_LONG);
        return constants;
    }

    @ReactMethod
    public void show(String message,int duration){
        Toast.makeText(getReactApplicationContext(),message,duration).show();
    }

ReactContextBaseJavaModule要求实现一个被调用的方法getName。此方法的目的是NativeModule在JavaScript中返回表示该类的字符串名称。所以在这里我们将调用它,ToastExample以便我们可以通过React.NativeModules.ToastExampleJavaScript 访问它。

  @Override
  public String getName() {
    return "ToastExample";
  }

一个可选的方法调用getConstants返回暴露给JavaScript的常量值。它的实现不是必需的,但对于需要同步从JavaScript到Java进行通信的关键预定义值非常有用。

  @Override
  public Map<String, Object> getConstants() {
    final Map<String, Object> constants = new HashMap<>();
    constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT);
    constants.put(DURATION_LONG_KEY, Toast.LENGTH_LONG);
    return constants;
  }

要向JavaScript公开方法,必须使用Java方法注释Java方法@ReactMethod。桥接方法的返回类型总是如此void。React Native桥是异步的,因此将结果传递给JavaScript的唯一方法是使用回调或发射事件(请参见下文)。

  @ReactMethod
  public void show(String message, int duration) {
    Toast.makeText(getReactApplicationContext(), message, duration).show();
  }

 

3.注册模块

Java中的最后一步是注册模块; 这发生在createNativeModules你的应用程序包中。如果模块未注册,则无法从JavaScript获得。

创建一个名为CustomToastPackage.javainside android/app/src/main/java/com/your-app-name/folder 的新Java类,其内容如下:


 
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Description:
 * Created by song on 2018/7/3.
 * email:bjay20080613@qq.com
 */
public class CustomToastPackage implements ReactPackage {
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules=new ArrayList<>();
        modules.add(new ToastModule(reactContext));
        return modules;
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}

该包需要getPackagesMainApplication.java文件的方法中提供。该文件存在于react-native应用程序目录中的android文件夹下。该文件的路径是:android/app/src/main/java/com/your-app-name/MainApplication.java

 

@Override
protected List<ReactPackage> getPackages() {
  return Arrays.<ReactPackage>asList(
      new MainReactPackage(),
      new CustomToastPackage()
  );
}

4.把原生模块包装到js模块中:

在react-native工程下,创建一个js文件;

文件中添加:

 

import {NativeModules} from 'react-native';
module.exports = NativeModules.ToastExample;

5.在App.js中调用原生模块:

 

//从android.js中导入
import ToastExample from './android';

const instructions = Platform.select({
  ios: 'Press Cmd+R to reload,\n' +
    'Cmd+D or shake for dev menu',
  android: 'Double tap R on your keyboard to reload,\n' +
    'Shake or press menu button for dev menu',
});

type Props = {};
export default class App extends Component<Props> {
  render() {
    return (
      <View style={styles.container}>
        //调用
        <Text style={styles.welcome} onPress={()=>ToastExample.show("js中点的啊",ToastExample.SHORT)}>
         调用原生Toast!
        </Text>
      </View>
    );
  }

}
2019-07-04 16:44:37 gs344937933 阅读数 844
  • 微服务和云原生架构实践

    通过剖析和展示一个端到端的简化微服务应用案例MovieApp,帮助学员学习理解现代微服务应用和云原生架构实践,内容包括: * 微服务应用架构 * 前后分离应用架构 * 基于Spring Security + JWT的微服务安全架构 * Spring Boot微服务应用开发和测试 * 基于React的前端应用开发 * Spring Cloud Gateway在微服务架构中的应用 * Docker Compose镜像构建和本地应用部署 * Kubernetes核心概念和应用部署 同时帮助学员熟悉现代应用开发技术栈, 包括: * Spring Boot ~ 开发框架 * Spring Security ~ 安全框架 * MyBatis ~ ORM框架 * JWT ~ 令牌框架 * React ~ 前端框架 * MySQL ~ 后端存储 * Spring Cloud Gateway ~ 微服务网关 * Zipkin ~ 调用链监控 * Docker Compose ~ 镜像构建和本地部署 * Kubernetes ~ 容器调度和部署 项目源码:https://github.com/jskillcloud/MovieApp

    4987 人正在学习 去看看 杨波

跨平台技术简介

针对原生开发面临问题,人们一直都在努力寻找好的解决方案,而时至今日,已经有很多跨平台框架,根据其原理,主要分为三类:

  • H5+原生(Cordova、Ionic、微信小程序)
  • JavaScript开发+原生渲染 (React Native、Weex、快应用)
  • 自绘UI+原生(QT for mobile、Flutter)

在接下来的章节中我们逐个来看看这三类框架的原理及优缺点。

Hybrid技术简介

H5+原生混合开发

这类框架主要原理就是将APP的一部分需要动态变动的内容通过H5来实现,通过原生的网页加载控件WebView (Android)或WKWebView(iOS)来加载。这样一来,H5部分是可以随时改变而不用发版,动态化需求能满足;同时,由于h5代码只需要一次开发,就能同时在Android和iOS两个平台运行,这也可以减小开发成本,也就是说,H5部分功能越多,开发成本就越小。我们称这种h5+原生的开发模式为混合开发 ,采用混合模式开发的APP我们称之为混合应用Hybrid APP ,如果一个应用的大多数功能都是H5实现的话,我们称其为Web APP 。

目前混合开发框架的典型代表有:Cordova、Ionic 和微信小程序,值得一提的是微信小程序目前是在webview中渲染的,并非原生渲染,但将来有可能会采用原生渲染。

混合开发技术点

如之前所述,原生开发可以访问平台所有功能,而混合开发中,H5代码是运行在WebView中,而WebView实质上就是一个浏览器内核,其JavaScript依然运行在一个权限受限的沙箱中,所以对于大多数系统能力都没有访问权限,如无法访问文件系统、不能使用蓝牙等。所以,对于H5不能实现的功能,都需要原生去做。而混合框架一般都会在原生代码中预先实现一些访问系统能力的API, 然后暴露给WebView以供JavaScript调用,这样一来,WebView就成为了JavaScript与原生API之间通信的桥梁,主要负责JavaScript与原生之间传递调用消息,而消息的传递必须遵守一个标准的协议,它规定了消息的格式与含义,我们把依赖于WebView的用于在JavaScript与原生之间通信并实现了某种消息传输协议的工具称之为WebView JavaScript Bridge, 简称 JsBridge,它也是混合开发框架的核心。

示例:JavaScript调用原生API获取手机型号

下面我们以Android为例,实现一个获取手机型号的原生API供JavaScript调用。在这个示例中将展示JavaScript调用原生API的流程,读者可以直观的感受一下调用流程。选用在Github上开源的dsBridge作为JsBridge来进行通信。dsBridge是一个支持同步调用的跨平台的JsBridge,此示例中只使用其同步调用功能。

  1. 首先在原生中实现获取手机型号的API getPhoneModel

    class JSAPI {
     @JavascriptInterface
     public Object getPhoneModel(Object msg) {
       return Build.MODEL;
     }
    }
    
  2. 将原生API通过WebView注册到JsBridge中

    import wendu.dsbridge.DWebView
    ...
    //DWebView继承自WebView,由dsBridge提供  
    DWebView dwebView = (DWebView) findViewById(R.id.dwebview);
    //注册原生API到JsBridge
    dwebView.addJavascriptObject(new JsAPI(), null);
    
  3. 在JavaScript中调用原生API

    var dsBridge = require("dsbridge")
    //直接调用原生API `getPhoneModel`
    var model = dsBridge.call("getPhoneModel");
    //打印机型
    console.log(model);
    

上面示例演示了JavaScript调用原生API的过程,同样的,一般来说优秀的JsBridge也支持原生调用JavaScript,dsBridge也是支持的,如果您感兴趣,可以去github dsBridge项目主页查看。

现在,我们回头来看一下,混合应用无非就是在第一步中预先实现一系列API供JavaScript调用,让JavaScript有访问系统的能力,看到这里,我相信你也可以自己实现一个混合开发框架了。

总结

混合应用的优点是动态内容是H5,web技术栈,社区及资源丰富,缺点是性能不好,对于复杂用户界面或动画,WebView不堪重任。

为什么80%的码农都做不了架构师?>>> ...

博文 来自: weixin_34292287

native API

阅读数 478

没有更多推荐了,返回首页