You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:57:06