如何在Cocos2d-x 3.14.1 Android应用中获取来电/挂断事件?
嘿,这个需求我之前在项目里刚好实现过!Cocos2d-x 3.x本身并没有直接封装Android电话状态的监听API,但我们可以通过Android原生代码+JNI调用的方式来实现,把来电和挂断事件传递到C++层处理。下面一步步给你讲清楚:
1. 实现Android原生的电话状态监听
首先我们需要在Android端创建一个广播接收器,用来监听系统的电话状态变化。
1.1 添加权限与广播配置
打开你的Android项目的AndroidManifest.xml,添加电话状态权限,以及注册广播接收器(如果用动态注册可以跳过静态注册部分):
<!-- 添加电话状态读取权限 --> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <!-- 静态注册广播接收器(可选,动态注册更推荐) --> <receiver android:name=".PhoneStateReceiver"> <intent-filter> <action android:name="android.intent.action.PHONE_STATE" /> </intent-filter> </receiver>
1.2 创建广播接收器类
在你的Android项目包路径下(比如com/yourgame/)创建PhoneStateReceiver.java,继承BroadcastReceiver并实现状态监听:
package com.yourgame; // 替换成你的项目包名 import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.telephony.TelephonyManager; import org.cocos2dx.lib.Cocos2dxJniHelper; public class PhoneStateReceiver extends BroadcastReceiver { // 定义事件类型常量,和C++层保持一致 private static final int EVENT_CALL_RINGING = 1; // 来电响铃 private static final int EVENT_CALL_HUNG_UP = 2; // 电话挂断(包括未接/通话结束) @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) { TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); switch (tm.getCallState()) { case TelephonyManager.CALL_STATE_RINGING: // 来电触发,通知C++层 Cocos2dxJniHelper.callStaticVoidMethod("org/cocos2dx/cpp/AppActivity", "onPhoneEvent", EVENT_CALL_RINGING); break; case TelephonyManager.CALL_STATE_IDLE: // 电话挂断触发,通知C++层 Cocos2dxJniHelper.callStaticVoidMethod("org/cocos2dx/cpp/AppActivity", "onPhoneEvent", EVENT_CALL_HUNG_UP); break; case TelephonyManager.CALL_STATE_OFFHOOK: // 电话接通事件(如果需要可以额外处理) break; } } } }
2. 通过JNI将事件传递到C++层
接下来需要在Android的AppActivity里做中转,把Java层的事件传递到C++的原生函数。
2.1 修改AppActivity.java
打开org/cocos2dx/cpp/AppActivity.java,添加静态方法和native声明:
package org.cocos2dx.cpp; import android.os.Build; import android.Manifest; import android.content.pm.PackageManager; import org.cocos2dx.lib.Cocos2dxActivity; public class AppActivity extends Cocos2dxActivity { // 供广播接收器调用的中转方法 public static void onPhoneEvent(int eventType) { nativeOnPhoneEvent(eventType); } // 声明native方法,对应C++层实现 private static native void nativeOnPhoneEvent(int eventType); // 动态申请权限(Android 6.0+必需) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (checkSelfPermission(Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.READ_PHONE_STATE}, 1001); } } // 可选:动态注册广播接收器(替代静态注册,兼容性更好) // phoneReceiver = new PhoneStateReceiver(); // IntentFilter filter = new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED); // registerReceiver(phoneReceiver, filter); } // 处理权限申请结果 @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 1001) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 权限获取成功,正常监听 } else { // 权限被拒绝,可提示用户开启权限 } } } // 如果用动态注册,记得在销毁时注销 // @Override // protected void onDestroy() { // super.onDestroy(); // if (phoneReceiver != null) { // unregisterReceiver(phoneReceiver); // } // } }
3. 在C++层处理电话事件
最后在Cocos2d-x的C++代码里实现native函数,处理来电和挂断逻辑。
3.1 声明与实现native函数
打开你的AppDelegate.h,添加函数声明:
#ifndef _APP_DELEGATE_H_ #define _APP_DELEGATE_H_ #include "cocos2d.h" class AppDelegate : private cocos2d::Application { // ... 原有代码 }; // 声明JNI函数 extern "C" { void Java_org_cocos2dx_cpp_AppActivity_nativeOnPhoneEvent(JNIEnv* env, jclass clazz, jint eventType); } #endif // _APP_DELEGATE_H_
然后在AppDelegate.cpp里实现函数和事件处理逻辑:
#include "AppDelegate.h" #include "cocos2d.h" using namespace cocos2d; // 自定义电话事件处理函数 void handlePhoneEvent(int eventType) { switch (eventType) { case 1: // 来电事件 CCLOG("[PhoneEvent] 收到来电,暂停游戏"); // 这里执行你的操作,比如暂停游戏、显示提示弹窗 Director::getInstance()->pause(); break; case 2: // 挂断事件 CCLOG("[PhoneEvent] 电话挂断,恢复游戏"); // 恢复游戏等操作 Director::getInstance()->resume(); break; default: break; } } // JNI函数实现 extern "C" { void Java_org_cocos2dx_cpp_AppActivity_nativeOnPhoneEvent(JNIEnv* env, jclass clazz, jint eventType) { handlePhoneEvent(eventType); } }
4. 关键注意事项
- 动态权限申请:Android 6.0(API 23)及以上,
READ_PHONE_STATE属于危险权限,必须动态申请,否则监听会失效。 - 广播注册方式:动态注册广播接收器比静态注册兼容性更好,尤其是在Android 8.0+系统中,静态广播的限制较多。
- 线程安全:JNI调用会在后台线程执行,如果你需要更新UI或操作Cocos2d-x的节点,记得切换到主线程(可以用
Director::getInstance()->getScheduler()->performFunctionInCocosThread())。
内容的提问来源于stack exchange,提问作者Beckon
相关产品推荐
相关产品推荐

