react-native 监听手机物理按键(音量键)

薛弘厚
2023-12-01

react-native 监听手机音量按键(结合原生安卓)

目的:监听手机的物理按键实现相应的功能(给自己的笔记)

Android KeyCode 可以自行网上查找
可根据相应 KeyEvent 进行手机按键事件拦截
可根据相应 KeyCode 执行你想要执行的内容

需求

-------- 实现进入指定页面后,使用音量键时执行自定义任务,而不是调节系统音量

解决方案

在 MainActivity.java 文件里添加如下方法(一样的不需要重复添加)

package com.demo; // 自己的包名

import com.facebook.react.ReactActivity;
import org.devio.rn.splashscreen.SplashScreen;
import android.os.Bundle;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.BroadcastReceiver;
import android.content.res.Configuration;
import android.view.WindowManager;
import android.view.KeyEvent;
import android.support.annotation.Nullable;

import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactMethod;

public class MainActivity extends ReactActivity {

    private NetworkChangeReceiver networkChangeReceiver;
    /*
	* isLister 音量键控制开关
	* true --- 音量键不可调节系统音量
	* flase --- 音量键可以调节系统音量
	*/
    Boolean isLister = false;

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Intent intent = new Intent("onConfigurationChanged");
        intent.putExtra("newConfig", newConfig);
        this.sendBroadcast(intent);
    }

    @Override
    protected String getMainComponentName() {
        return "demoApp";
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        SplashScreen.show(this, com.demo.R.style.SplashScreenTheme);
        super.onCreate(savedInstanceState);

        /*
        * 主要是RN端不能直接执行MainActivity里面的方法所以需要另外创建可供RN执行的module
        * 利用module里面的方法来改变 isLister 的值实现开关功能 
        */
        // 注册自定义广播 (音开关广播)
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("com.demo.volume"); // com.demo.volume 命名随意
        networkChangeReceiver = new NetworkChangeReceiver();
        registerReceiver(networkChangeReceiver, intentFilter);
    }

    // 音频开关
    private class NetworkChangeReceiver extends BroadcastReceiver {
      // 收到广播执行的内容
      @Override
      public void onReceive(Context context, Intent intent) {
      	// 获取广播中传入的 isLister 的值, 获取不到时取第二个参数,这里是 false 
        isLister = intent.getBooleanExtra("isLister", false);
      }
    }

    // 发送事件给RN端 的方法
    private void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params) {
        reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, params);
    }

    // 监听手机按键
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        ReactContext reactContext = getReactInstanceManager().getCurrentReactContext();
        WritableMap params = Arguments.createMap();
        params.putInt("keyCode", event.getKeyCode());
        if (event.getAction() == KeyEvent.ACTION_DOWN) {
            // 发送keydown事件给RN端
            sendEvent(reactContext, "keydown", params); // keydown 可自己命名
        } else if (event.getAction() == KeyEvent.ACTION_UP) {
        	// 发送keyup事件给RN端
            sendEvent(reactContext, "keyup", params);  // keyup 可自己命名
        }
        return super.dispatchKeyEvent(event);
    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
      // 覆盖音量键弹起事件 (这样就不会出现调节音量的弹窗)
      // 也可以自己根据别的 KeyEvent 事件来拦截相应操作
      if (isLister && keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
          return true;
      } else if (isLister && keyCode == KeyEvent.KEYCODE_VOLUME_UP){
          return true;
      } else {
          return super.onKeyUp(keyCode, event);
      }
    }

    public boolean onKeyDown(int keyCode, KeyEvent event) {
      // 覆盖音量键按下事件 (这样就不会出现调节音量的弹窗)
      if (isLister && keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
          return true;
      } else if (isLister && keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
          return true;
      } else {
          return super.onKeyDown(keyCode, event);
      }
    }

}
  1. 在 MainActivity.java 的同级目录下新建 keyeventlister 文件夹
  2. 在 keyeventlister 文件夹下新建 KeyEventListerModule.java
package com.demo.keyeventlister; // 自己的包名 + keyeventlister

import android.content.Intent;

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

public class KeyEventListerModule extends ReactContextBaseJavaModule{
    private ReactApplicationContext mContext;
    KeyEventListerModule(ReactApplicationContext reactContext) {
        super(reactContext);
        mContext = reactContext;
    }


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

    // 开关音量键 (提供给RN端使用的方法)
    @ReactMethod
    public void audioSwitch(final Boolean isLister) {
      getCurrentActivity().runOnUiThread(new Runnable() {
        @Override
        public void run() {
          Intent intent = new Intent();
          intent.putExtra("isLister", isLister); // 添加广播传送的参数
          intent.setAction("com.demo.volume"); // 需跟注册广播时填写的一致
          //发送广播
          getCurrentActivity().sendBroadcast(intent);
        }
      });
    }
}

在 keyeventlister 文件夹下创建 KeyEventListerPackage.java

package com.demo.keyeventlister;

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;

public class KeyEventListerPackage implements ReactPackage {

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

    @Override
    public List<NativeModule> createNativeModules(
            ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();

        modules.add(new KeyEventListerModule(reactContext));

        return modules;
    }

}

修改 MainApplication.java

// 在头部引入
import com.demo.keyeventlister.KeyEventListerPackage; 

@Override
 protected List<ReactPackage> getPackages() {
   return Arrays.<ReactPackage>asList(
	   // 这里添加如下package ↓↓↓
       new KeyEventListerPackage()
   );
 }

使用方法

Example.js

import React, { Component } from 'react';
import { View, NativeModules } from 'react-native';
export default class Example extends Component {
  constructor(props) {
    super(props);
    this.state = {
    
    }
    
    keyEvent = null;
  }
  componentDidMount() {
  	// 进入页面使手机音量按键失效
    NativeModules.KeyEventLister.audioSwitch(true); // 拦截手机音量按键事件
    // 编写自己的按键事件
    this.keyEvent = DeviceEventEmitter.addListener('keyup', (e) => {
    	if (e.keyCode === 24) {
			// 音量增加键 
		} else if () {
			// 音量减小键
		}	
		console.log(e.keyCode)
   	})
  }

  componentWillUnmount() {
    // 恢复手机音量按键原本功能
    NativeModules.KeyEventLister.audioSwitch(false); // 取消拦截手机音量按键事件
    if (this.keyEvent) {
      // 移除事件监听
      this.keyEvent.remove();
    }
  }

  render() {
	return (
		<View></View>
    )
  }
}

 类似资料: