跳至主要內容

React Native 桥接原生

ZiHao...大约 7 分钟前端跨平台前端React Native

桥接原生方法

  1. 在原生文件中找到 MainApplication,里面的 getPackages,就是用来注册自己写的原生应用
image.png
image.png
  1. 创建自己的这个原生应用

image.png
先创建 DemoPackage 文件类型是 class,名字自己定,测试一下

package com.awesomeproject.bewwarchitecture.Rn.RN;

import androidx.annotation.NonNull;

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.List;

public class DemoPackage implements ReactPackage {

    @NonNull
    @Override
    //原生方法
    public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactApplicationContext) {
        List<NativeModule>  modules = new ArrayList<>();
        modules.add(new AppModule(reactApplicationContext));
        return modules;
    }

    @NonNull
    @Override
    //原生组件
    public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactApplicationContext) {
        return new ArrayList<>();
    }
}

然后:创建 Appmodule.java 继承 ReactContextBaseJavaModule 这个基类

package com.awesomeproject.bewwarchitecture.Rn.RN;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

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

public class AppModule extends ReactContextBaseJavaModule {
    public AppModule(){
        super();
    }
    public AppModule(@Nullable ReactApplicationContext reactContent){
        super(reactContent);
    }
    @NonNull
    @Override
    public String getName() {   //定义的是调用原生时的名字
        return "APP";
    }
    //写一个有返回值的原生方法。因为这是异步的不能直接return 数据,这里使用了Promise
    @ReactMethod
    public void openGallery(Promise promise) {
        String versiontext = BuildConfig.VERSION_NAME;
        if (versiontext == null) {
            promise.reject(new Throwable("错误"));
        } else {
            promise.resolve(versiontext);
        }

    }
}

  1. 调用原生

需要引入一个模块 NativeModules ,从 NativeModules 中引出刚才在原生中注册的 APP

import React, { FC, useMemo, useState } from "react";
import { Button, SafeAreaView, View, NativeModules } from "react-native";
import Theme from "./src/content/Theme";
import Refinput from "./src/modules/Ref";
const App: FC<any> = () => {
  return (
    <SafeAreaView>
      <Theme.Provider value={{ modal: "dark" }}>
        <View>
          <Refinput />
          <Button
            title="调用原生"
            onPress={() => {
              const { APP } = NativeModules;
              APP?.openGallery().then((res: any) => {
                console.log(res);
              });
            }}
          ></Button>
        </View>
      </Theme.Provider>
    </SafeAreaView>
  );
};
export default App;

桥接原生原子组件

  1. 先创建原生组件,在 res layout 文件夹中 创建一个 xml 文件,样式先随便写一个
image.png
image.png
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation='horizontal'
  android:layout_width='match_parent'
  android:layout_height="match_parent"
  android:paddingHorizontal="16dp"
  android:paddingVertical="10dp"
  >
  <ImageView
    android:id="@+id/image"
    android:layout_width="96dp"
    android:layout_height="96dp"

    android:src="@drawable/autofill_inline_suggestion_chip_background"
    />

  <LinearLayout
    android:layout_width='match_parent'
    android:layout_height="wrap_content"
    android:layout_marginLeft="16dp"
    android:orientation='vertical'>
    <TextView
      android:id="@+id/text2"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:text="尼古拉斯赵四"
      android:textColor="#333333"
      android:textSize="20sp"
      android:textStyle="bold" />
    <TextView
      android:id="@id/text2"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:text="爱我家低哦啊未见动静啊我就案件我的就爱我家低偶爱叫我第几啊我第几啊我i就"
      android:textColor="#333333"
      android:textSize="20sp"
      android:textStyle="bold" />
  </LinearLayout>
</LinearLayout>
image.png
image.png
  1. 注册组件,

创建在 view 文件夹中创建 InfoView 组件
image.png

package com.awesomeproject.bewwarchitecture.Rn.view;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;

import com.awesomeproject.R;

public class InfoView extends LinearLayout { //继承LinearLayout
    public InfoView(Context context) {
        super(context);
        initView(); //执行一下
    }
    private void initView(){
        //原生代码,看不懂
        View view = LayoutInflater.from(getContext()).inflate(R.layout.initview,null);
        LayoutParams lp  = new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
        this.addView(view,lp);
    }
}

  1. 创建 viewmanage 文件夹,管理原生组件
image.png
image.png
package com.awesomeproject.bewwarchitecture.Rn.viewmanage;

import android.view.View;

import androidx.annotation.NonNull;

import com.awesomeproject.bewwarchitecture.Rn.view.InfoView;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;

public class InfoViewManage extends SimpleViewManager<InfoView> {

    @NonNull
    @Override
    public String getName() {
        return "NativeInfo_view"; //在React中引用是,填写的名字
    }

    @NonNull
    @Override
    protected InfoView createViewInstance(@NonNull ThemedReactContext context) {
      return  new InfoView(context); //这是刚刚在view文件中写的那个文件,new一下
    }
}

  1. 在 Demopackage 中,添加进去上一步写的 InfoViewManage
package com.awesomeproject.bewwarchitecture.Rn.RN;

import androidx.annotation.NonNull;

import com.awesomeproject.bewwarchitecture.Rn.viewmanage.InfoViewManage;
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.List;

public class DemoPackage implements ReactPackage {

    @NonNull
    @Override
    //原生方法
    public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactApplicationContext) {
        List<NativeModule>  modules = new ArrayList<>();
        modules.add(new AppModule(reactApplicationContext));
        return modules;
    }

    @NonNull
    @Override
    //原生组件
    public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactApplicationContext) {
        List<ViewManager>  viewManagers = new ArrayList<>();
        viewManagers.add(new InfoViewManage());
        return  viewManagers;
    }
}

  1. 在 React 中使用
import React, {FC} from 'react';
import {
  View,
  Text,
  StyleSheet,
  requireNativeComponent,//借助此方法
  ViewProps,
} from 'react-native';
interface Props {
  name?: string;
}
type NativeInfoviewType = ViewProps | {};
const Nativeview2 =
  requireNativeComponent<NativeInfoviewType>('NativeInfo_view');//引入写的原生组件
const Infoview: FC<Props> = () => {
  return (
    <View style={styles.container}>
      <Text>Hello</Text>
      <Nativeview2 style={styles.container} />//直接使用
    </View>
  );
};
const styles = StyleSheet.create({
  container: {
    width: '100%',
    height: '100%',
  },
});
export default Infoview;

image.png
image.png

桥接原生组件之传递数据 props 属性值

  1. 在原生组件 Infoview 中
package com.awesomeproject.bewwarchitecture.Rn.view;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.awesomeproject.R;
import com.bumptech.glide.Glide;

import java.time.Instant;

public class InfoView extends LinearLayout {
    ImageView avaterImg;  // 头像图片控件
    TextView nameText;     // 名称文本控件
    TextView descText;     // 描述文本控件

    public InfoView(Context context) {
        super(context);
        initView();
    }

    private void initView() {
        // 加载 InfoView 的布局文件
        View view = LayoutInflater.from(getContext()).inflate(R.layout.initview, null);

        // 查找并初始化控件   根据infoview中的组件id  找到这些控件
        avaterImg = view.findViewById(R.id.image);
        nameText = view.findViewById(R.id.name);
        descText = view.findViewById(R.id.desc);

        // 设置布局参数并将 view 添加到 InfoView
        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        this.addView(view, lp);
    }

    public void Setavater(String url) {
        // 使用 Glide 库加载并显示头像图片
        Glide.with(this).load(url).into(avaterImg);
    }

    public void Setname2(String name) {
        // 设置名称文本
        nameText.setText(name);
    }
}
  1. 在 viewmanage 中,声明为 React 中可以使用的组件属性
package com.awesomeproject.bewwarchitecture.Rn.viewmanage;

import android.view.View;

import androidx.annotation.NonNull;

import com.awesomeproject.bewwarchitecture.Rn.view.InfoView;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.annotations.ReactProp;

public class InfoViewManage extends SimpleViewManager<InfoView> {

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

    @NonNull
    @Override
    protected InfoView createViewInstance(@NonNull ThemedReactContext context) {
        // 创建并返回 InfoView 实例
        return new InfoView(context);
    }

    @ReactProp(name = "avater")
    public void setAvatar(InfoView view, String url) {
        // 设置头像图片
        view.setAvatar(url);
    }

    @ReactProp(name = "name")
    public void setName(InfoView view, String name) {
        // 设置名称文本
        view.setName(name);
    }
}
  1. 在 React 中进行使用
import React, { FC } from "react";
import {
  View,
  Text,
  StyleSheet,
  requireNativeComponent,
  ViewProps,
} from "react-native";
interface Props {
  name?: string;
}
type NativeInfoviewType =
  | ViewProps
  | {
      avater: string;
      name: string;
    };
const Nativeview2 =
  requireNativeComponent<NativeInfoviewType>("NativeInfo_view");
const Infoview: FC<Props> = () => {
  return (
    <View style={styles.container}>
      <Text>Hello</Text>
      <Nativeview2
        avater={
          "https://p6-passport.byteacctimg.com/img/user-avatar/6971cbaa33a2f797512b9bfb86732e02~90x90.awebp"
        }
        name={"赵子豪"}
        style={styles.container}
      />
    </View>
  );
};
const styles = StyleSheet.create({
  container: {
    width: "100%",
    height: "100%",
  },
});
export default Infoview;

原生组件回调 JS 层方法

  1. 首先先给原生组件添加一个按钮,并绑定事件
//添加一个按钮 ID是button
<Button
  android:id="@+id/button"
  android:layout_width="100dp"
  android:layout_height="40dp"
  android:text="改变形状" />
  1. 再 infoView 中绑定事件
package com.awesomeproject.bewwarchitecture.Rn.view;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.awesomeproject.R;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.CircleCrop;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.RCTEventEmitter;
//继承一下View.OnClickListener,
public class InfoView extends LinearLayout implements View.OnClickListener {

    private ImageView avatarImg;
    private TextView nameText;
    private TextView descText;
    private Button button;
    private String shape = "circle";
    private String url = "";

    public InfoView(Context context) {
        super(context);
        initView();
    }

    private void initView() {
        View view = LayoutInflater.from(getContext()).inflate(R.layout.initview, null);
        avatarImg = view.findViewById(R.id.image);
        button = view.findViewById(R.id.button);
        nameText = view.findViewById(R.id.name);
        descText = view.findViewById(R.id.desc);
        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        this.addView(view, lp);

        button.setOnClickListener(this);
    }

    public void setAvatar(String url) {
        this.url = url;
        Glide.with(getContext())
        .load(url)
        .placeholder(R.drawable.autofill_inline_suggestion_chip_background)
        .into(avatarImg);
    }

    public void setName(String name) {
        nameText.setText(name);
    }
	//新增的点击事件,切换头像圆角的一个效果
    @Override
    public void onClick(View v) {
        if (shape.equals("circle")) {
            shape = "round";
        } else {
            shape = "circle";
        }
        Glide.with(getContext())
        .load(url)
        .placeholder(R.drawable.rn_edit_text_material)
        .transform(shape.equals("circle") ? new CircleCrop() : new RoundedCorners(80))
        .into(avatarImg);
        WritableMap parmas = Arguments.createMap();
        //向JS层返回shape信息
        parmas.putString("shape",this.shape);
        ReactContext context = (ReactContext)getContext();
        //向外暴露的事件名是onShapeChange
        context.getJSModule(RCTEventEmitter.class).receiveEvent(getId(),"onShapeChange",parmas);
    }
}
  1. 在 infoViewManage 中向 JS 层暴露这个属性

添加以下代码


    @Nullable
    @Override
    public Map getExportedCustomBubblingEventTypeConstants() {
        return MapBuilder.builder().put("onShapeChange",MapBuilder.of(
                "phasedRegistrationNames",
                MapBuilder.of("bubbled","onShapeChange")
        )).build();
    }
  1. React 中使用
<Nativeview2
  avater={userinfo.httpsimg}
  name={"赵子豪"}
  onShapeChange={(e: any) => {
    console.log(e.nativeEvent.shape);
  }}
  style={styles.container}
/>

函数回调成功
image.png

公开原生组件方法给 JS 层调用

  1. 在 infoViewManage.java 中添加以下方法
public static final int SET_SHAPE_CODE = 100;//标志码
@Override
public Map<String, Integer> getCommandsMap() {
    return MapBuilder.of("setShape", SET_SHAPE_CODE);
}
@Override
public void receiveCommand(@NonNull InfoView Infoview ,String commandId, @Nullable ReadableArray args) {
    int commend = Integer.parseInt(commandId);
    if(commend == SET_SHAPE_CODE){
        if(args !=null && args.size() >0){
            String shape = args.getString(0);
            Infoview.setShape(shape);
        }
    }else{
        super.receiveCommand(Infoview, commend, args);
    }

}
  1. 在 infoview.java 中 添加以下代码
 public void setShape(String shape){
        this.shape = shape;
        Glide.with(getContext())
                .load(url)
                .placeholder(R.drawable.autofill_inline_suggestion_chip_background)
                .transform(shape.equals("circle") ? new CircleCrop() : new RoundedCorners(80))
                .into(avatarImg);
    }
  1. 在 React 中使用
const Infoview: FC<Props> = () => {
  const viewID = useRef(null);
  const sendcommend = (commend: string, params: any[]) => {
    const viewid = findNodeHandle(viewID.current);
    // @ts-ignore
    const commands = UIManager.NativeInfo_view.Commands[commend].toString();
    UIManager.dispatchViewManagerCommand(viewid, commands, params);
  };
  useEffect(() => {
    setTimeout(() => {
      sendcommend("setShape", ["circle"]); //两秒后执行原生组件方法
    }, 2000);
  }, []);
  return (
    <View style={styles.container}>
      <Text>Hello</Text>
      <Nativeview2
        ref={viewID}
        avater={userinfo.httpsimg}
        name={"赵子豪"}
        onShapeChange={(e: any) => {
          console.log(e.nativeEvent.shape);
        }}
        style={styles.container}
      />
    </View>
  );
};
你认为这篇文章怎么样?
  • 0
  • 0
  • 0
  • 0
  • 0
  • 0
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.15.5