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);
}
}
}
- 在 MainActivity.java 的同級目錄下建立 keyeventlister 檔案夾
- 在 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>
)
}
}