天天看點

react-native 監聽手機實體按鍵(音量鍵)react-native 監聽手機音量按鍵(結合原生安卓)

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>
    )
  }
}

           

繼續閱讀