You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android应用实现GSM来电转发失败求助:已配置权限与Receiver

搞定GSM来电转发失效的问题

嘿,我帮你梳理下可能导致功能失效的几个关键点,咱们一步步排查:

1. 权限没到位:动态申请不能少

从Android 6.0开始,CALL_PHONEREAD_PHONE_STATE这类危险权限光在Manifest里写没用,必须运行时动态申请。看你截断的权限代码,估计还缺了获取来电号码必需的READ_PHONE_STATE,甚至Android 8.0+还要ANSWER_PHONE_CALLS权限。

先补全Manifest权限:

<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- Android 8.0+ 处理来电必备 -->
<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />

然后在代码里动态申请:

在你的主Activity里加这段代码,确保用户授予权限:

private static final int PERMISSION_REQUEST = 100;
private String[] neededPermissions = {
    Manifest.permission.CALL_PHONE,
    Manifest.permission.READ_PHONE_STATE,
    Manifest.permission.ANSWER_PHONE_CALLS
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        boolean hasAllPermissions = true;
        for (String perm : neededPermissions) {
            if (checkSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) {
                hasAllPermissions = false;
                break;
            }
        }
        if (!hasAllPermissions) {
            requestPermissions(neededPermissions, PERMISSION_REQUEST);
        }
    }
}

// 处理权限申请结果
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == PERMISSION_REQUEST) {
        boolean allGranted = true;
        for (int result : grantResults) {
            if (result != PackageManager.PERMISSION_GRANTED) {
                allGranted = false;
                break;
            }
        }
        if (!allGranted) {
            Toast.makeText(this, "得授予所有权限才能用转发功能哦", Toast.LENGTH_SHORT).show();
        }
    }
}

2. 广播Receiver注册错了:Android 8.0+不支持静态注册系统广播

你如果是在Manifest里静态注册的PHONE_STATE接收器,那大概率收不到广播——Android 8.0之后,大部分系统广播只能动态注册

改成动态注册:

在主Activity的onCreate里注册,onDestroy里注销,避免内存泄漏:

private PhoneStateReceiver myReceiver;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // 初始化接收器
    myReceiver = new PhoneStateReceiver();
    // 过滤来电状态变化的广播
    IntentFilter filter = new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
    registerReceiver(myReceiver, filter);
}

@Override
protected void onDestroy() {
    super.onDestroy();
    // 记得注销!
    if (myReceiver != null) {
        unregisterReceiver(myReceiver);
    }
}

Manifest里的静态注册可以留着,但主要靠动态注册触发。

3. 转发逻辑有坑:不能直接在来电时拨打电话

这里要注意:设备正在响铃时,直接调用ACTION_CALL会被系统拦截,因为不允许同时存在两个通话。得换个方式:

正确的转发流程:

  1. 在Receiver里监听到来电,获取号码后,启动一个Service来处理转发
  2. 在Service里加个短暂延迟(比如3秒),等当前来电状态稳定后再拨打目标号码

接收器代码示例:

public class PhoneStateReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(intent.getAction())) {
            TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
            String callState = tm.getCallState();
            
            // 监听到来电响铃
            if (TelephonyManager.CALL_STATE_RINGING.equals(callState)) {
                String incomingNum = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
                if (incomingNum != null && !incomingNum.isEmpty()) {
                    // 启动Service处理转发
                    Intent serviceIntent = new Intent(context, ForwardCallService.class);
                    serviceIntent.putExtra("INCOMING_NUM", incomingNum);
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                        context.startForegroundService(serviceIntent);
                    } else {
                        context.startService(serviceIntent);
                    }
                }
            }
        }
    }
}

Service代码示例:

public class ForwardCallService extends Service {
    // 替换成你的目标号码
    private static final String TARGET_NUMBER = "13xxxxxxxxx";

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        String incomingNum = intent.getStringExtra("INCOMING_NUM");
        
        // 延迟3秒再拨打,避免和当前来电冲突
        new Handler(Looper.getMainLooper()).postDelayed(() -> {
            Intent callIntent = new Intent(Intent.ACTION_CALL);
            callIntent.setData(Uri.parse("tel:" + TARGET_NUMBER));
            callIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            try {
                startActivity(callIntent);
            } catch (SecurityException e) {
                e.printStackTrace();
                Toast.makeText(this, "权限不够,没法拨打~", Toast.LENGTH_SHORT).show();
            }
        }, 3000);
        
        return START_NOT_STICKY;
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

4. 厂商ROM的坑:别忘了加后台白名单

很多国产手机(小米、华为、OPPO等)有后台限制,就算代码没问题,也可能被系统杀进程或者拦截广播。你需要:

  • 把应用加入后台运行白名单
  • 允许应用自启动
  • 手动检查应用权限里的“电话”相关权限是否都开启

最后,建议你先加Log日志,验证Receiver是否能收到广播、权限是否都授予,再一步步调试转发逻辑。

内容的提问来源于stack exchange,提问作者Jyoti

火山引擎 最新活动