(五)react-native開發系列之Android原生交互


react-native可以做web與原生的交互,這是使用react-native開發項目的主要目的之一,也是主要優勢,用rn而不用原生交互則毫無價值,這篇文章用來記錄在項目中rn的原生交互使用過程。

之前說過要做的是一個pda項目,所以今天以input獲取焦點的時候禁止軟鍵盤彈出為例,大體說一下rn的原生交互過程。

android的原生交互分為以下幾步

  1. 編寫原生代碼
  2. 向js暴露原生接口 
  3. 注冊原生模塊
  4. 導出並再rn導入原生,模塊

1、編寫原生模塊

作為web工程師出身的我,對原生android代碼是不太了解的,充其量也只是稍微了解點java語言,但是通過自己的努力,還是過來了(笑哭);根據需求,就是再剛一進入頁面的時候,讓第一個input獲取焦點,並同時隱藏軟鍵盤,前端代碼很好寫,就是在獲取焦點之后調用隱藏軟鍵盤的原生功能;搞清楚了需求之后就開始編寫原生代碼了。

如上圖,在newpda目錄下面新建BoardModule類文件,用來編寫原生功能代碼;這個類繼承自 ReactContextBaseJavaModule,代碼如下

package com.newpda;
import android.util.Log;
import android.widget.Toast;
import android.widget.EditText;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import java.lang.reflect.Method;

import java.util.HashMap;
import java.util.Map;
import android.content.Context;
import android.app.Activity;
import android.app.ActivityManager;
import android.view.inputmethod.InputMethodManager;
import com.facebook.infer.annotation.Assertions;
import javax.annotation.Nullable;

/**
 * Description: Created by song on 2018/7/3. email:gaosongai@foxmail.com
 */
public class BoardModule extends ReactContextBaseJavaModule {
    private final ReactApplicationContext reactContext;  
    public BoardModule(ReactApplicationContext reactContext) {
        super(reactContext);
        this.reactContext = reactContext;   // 獲取上下文
    }

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

    /**
     *    關閉Edittext軟件盤,光標依然正常顯示。 
     */
    @ReactMethod
    public void hideboard() {
        Activity currentActivity = getCurrentActivity();
        InputMethodManager mInputMethodManager = (InputMethodManager)
        Assertions.assertNotNull(this.reactContext.getSystemService(Context.INPUT_METHOD_SERVICE));
        mInputMethodManager.hideSoftInputFromWindow(currentActivity.getCurrentFocus().getWindowToken(), 0);
    }
}

hideboard為隱藏軟鍵盤的方法,並向js暴露hideboard方法,要導出一個方法給JavaScript使用,Java方法需要使用注解@ReactMethod

2、注冊模塊

然后注冊原生模塊,同級目錄下新建CustomBoardPackage類,代碼如下

package com.newpda;

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/9/6.
 * email:gaosongai@foxmail.com
 */
public class CustomBoardPackage implements ReactPackage {
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules=new ArrayList<>();
        modules.add(new BoardModule(reactContext));
        return modules;
    }

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

我們需要在應用的Package類的createNativeModules方法中添加這個模塊。如果模塊沒有被注冊,它也無法在JavaScript中被訪問到。

然后這個package需要在MainApplication.java文件的getPackages方法中提供,文件在同級目錄下,代碼如下

package com.newpda;

import android.app.Application;

import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;

import java.util.Arrays;
import java.util.List;

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 CustomBoardPackage()   // 剛剛添加的方法
      );
    }

    @Override
    protected String getJSMainModuleName() {
      return "index";
    }
  };

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

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

3、在rn中引入模塊

為了讓你的功能從JavaScript端訪問起來更為方便,通常我們都會把原生模塊封裝成一個JavaScript模塊。這不是必須的,但省下了每次都從NativeModules中獲取對應模塊的步驟。這個JS文件也可以用於添加一些其他JavaScript端實現的功能,App.js同級目錄下新建androidtoast.js,內容如下

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

然后在組件內部使用

import BoardModule from "../../../androidtoast";
BoardModule.hideboard();  // 使用原生模塊方法


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM