开发适配cordova-plugin-tts的Cordova来电监听通知插件需求问询
Hey there! I get that you've been grinding on this plugin for a month—totally feel the pain of trial-and-error when you're new to these tools. Let's get your incoming call listener working with cordova-plugin-tts so it stops playing audio during calls and gives a proper notification.
Core Issue Breakdown
Right now, when an incoming call comes in, Android doesn't automatically pause third-party audio like your TTS. We need to:
- Listen for incoming call state changes (ringing, active, ended)
- Trigger
cordova-plugin-ttsto pause when a call starts, then resume when it ends - Make sure your plugin has the right permissions and broadcast setup to detect calls
Step 1: Complete the Java Plugin Code
Here's a full, corrected version of your Java code (filling in the gaps from your snippet). This will register a broadcast receiver to detect call states and communicate with your Cordova app:
package com.caller.notifier; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.telephony.TelephonyManager; import org.apache.cordova.CordovaPlugin; import org.apache.cordova.CallbackContext; import org.json.JSONArray; import org.json.JSONException; public class CallNotifier extends CordovaPlugin { private BroadcastReceiver callReceiver; private CallbackContext callbackContext; @Override public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { this.callbackContext = callbackContext; if (action.equals("startListening")) { startCallListener(); callbackContext.success("Call listener started"); return true; } else if (action.equals("stopListening")) { stopCallListener(); callbackContext.success("Call listener stopped"); return true; } return false; } private void startCallListener() { callReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE); // Send call state to JS layer to control TTS if (state != null) { switch (state) { case TelephonyManager.EXTRA_STATE_RINGING: // Notify JS to pause TTS and show call notification cordova.getActivity().runOnUiThread(() -> { callbackContext.success("{\"state\":\"ringing\"}"); }); break; case TelephonyManager.EXTRA_STATE_OFFHOOK: // Call is active, keep TTS paused cordova.getActivity().runOnUiThread(() -> { callbackContext.success("{\"state\":\"active\"}"); }); break; case TelephonyManager.EXTRA_STATE_IDLE: // Call ended, resume TTS cordova.getActivity().runOnUiThread(() -> { callbackContext.success("{\"state\":\"idle\"}"); }); break; } } } }; // Register the broadcast receiver IntentFilter filter = new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED); cordova.getActivity().registerReceiver(callReceiver, filter); } private void stopCallListener() { if (callReceiver != null) { try { cordova.getActivity().unregisterReceiver(callReceiver); } catch (IllegalArgumentException e) { // Ignore if receiver wasn't registered } } } @Override public void onDestroy() { super.onDestroy(); stopCallListener(); // Clean up receiver when app closes } }
Step 2: Fix plugin.xml Configuration
Make sure your plugin.xml has the right permissions, intent filters, and plugin setup. Here's the corrected section:
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" id="com.caller.notifier" version="1.0.0"> <name>CallNotifier</name> <description>Cordova plugin to listen for incoming calls and control TTS</description> <author>Your Name</author> <license>MIT</license> <engines> <engine name="cordova" version=">=9.0.0"/> </engines> <platform name="android"> <config-file target="AndroidManifest.xml" parent="/manifest"> <!-- Required permission to read phone state --> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <!-- For Android 12+, need POST_NOTIFICATIONS to show call alerts --> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> </config-file> <source-file src="src/android/com/caller/notifier/CallNotifier.java" target-dir="src/com/caller/notifier" /> <js-module name="CallNotifier" src="www/CallNotifier.js"> <clobbers target="window.CallNotifier" /> </js-module> </platform> </plugin>
Step 3: Add the JS Layer to Control TTS
Create a www/CallNotifier.js file to bridge the Java plugin with cordova-plugin-tts:
var exec = require('cordova/exec'); var CallNotifier = { startListening: function(successCallback, errorCallback) { exec(function(result) { var callState = JSON.parse(result); switch(callState.state) { case 'ringing': // Pause TTS and show a notification if(window.TTS) { window.TTS.pause(); } alert("Incoming call!"); // Replace with a custom notification if needed break; case 'active': // Keep TTS paused if(window.TTS) { window.TTS.pause(); } break; case 'idle': // Resume TTS after call ends if(window.TTS) { window.TTS.resume(); } break; } successCallback(result); }, errorCallback, 'CallNotifier', 'startListening', []); }, stopListening: function(successCallback, errorCallback) { exec(successCallback, errorCallback, 'CallNotifier', 'stopListening', []); } }; module.exports = CallNotifier;
Step 4: Use the Plugin in Your App
In your main Cordova app JS, initialize both plugins and start the call listener:
document.addEventListener("deviceready", function() { // Initialize TTS first window.TTS .init({ lang: 'en-US' }) .then(() => { console.log('TTS initialized'); // Start listening for calls window.CallNotifier.startListening( function(result) { console.log('Call state:', result); }, function(error) { console.error('Call listener error:', error); } ); }) .catch((err) => { console.error('TTS init failed:', err); }); }, false);
Key Notes for Beginners
- Permissions: On Android 6+, you'll need to request runtime permissions for
READ_PHONE_STATEandPOST_NOTIFICATIONS. You can usecordova-plugin-android-permissionsto handle this. - Testing: Use the Android Studio emulator to simulate incoming calls (go to More > Phone > Enter a number > Call).
- Cleanup: Always unregister the broadcast receiver when the app closes to avoid memory leaks (the
onDestroymethod in Java handles this).
内容的提问来源于stack exchange,提问作者user9757264

