替换原生来电应用---杀进程无法唤醒问题

2019-06-03  本文已影响0人  走在冷风中吧

前言

公司最近新出产品, 需要定制系统来电界面, 项目接近尾声, 写篇帖子记录下~
关于来电的监听, 网上有很多帖子, 大多是通过监听来电的广播来实现的, 存在的弊端在于: 电话监听广播需要用户手动授权后才会生效, 如果用户拒绝授权, 那这个功能就gg了.
在Android6.0+ google提供了开发者可以手动开启替换来电应用的权限, 且经过测试功能很稳定,所以我们采用这种方式进行开发.
具体来电功能的实现,参考https://www.jianshu.com/p/4ae2a7512787 Android替换原生电话应用的帖子.

问题

上述大神的帖子, 基本可以实现来电替换的效果, 但是仍然有些bug和不完善的地方, 主要问题在于: 当杀掉app的进程后, 再接入电话, 或者呼出, 会出现只震动, 无通话界面的现象, 于是出现了这篇帖子~

分析原因1

以下是原贴中唤起来电界面的方案:

Override
public void onCallAdded(Call call) {
    super.onCallAdded(call);

    call.registerCallback(callback);
    PhoneCallManager.call = call; // 传入call
    
    CallType callType = null;

    if (call.getState() == Call.STATE_RINGING) {
        callType = CallType.CALL_IN;
    } else if (call.getState() == Call.STATE_CONNECTING) {
        callType = CallType.CALL_OUT;
    }


    if (callType != null) {
        Call.Details details = call.getDetails();
        String phoneNumber = details.getHandle().toString().substring(4)
                .replaceAll("%20", ""); // 去除拨出电话中的空格
//  在这里打开来电界面 楼主采用一个比较少见的再activity中写静态方法来开启自己
//        PhoneCallActivity.actionStart(this, phoneNumber, callType);
// 这里我在写的时候采用了startActivity方法, 所以导致了无法开启页面问题
        startActivity(xxxxx)
    }
}

在杀进程后, 在一个未激活的进程中,service无法直接唤醒一个activity

解决方案1

一次误打误撞的实验中发现, 杀进程后在brocastreceiver中可以打开activity, 问题解决~
附上代码:
PhoneService

    @Override
    public void onCallAdded(Call call) {
        super.onCallAdded(call);
        call.registerCallback(callback);
        Log.e("lily","onCallAdded");
        PhoneCallManager.call = call;

        CallType callType = null;
        if (call.getState() == Call.STATE_RINGING) { //来电
            callType = CallType.CALL_IN;
        } else if (call.getState() == Call.STATE_CONNECTING) { //去电
            callType = CallType.CALL_OUT;
        }

        if (callType != null) {
            Call.Details details = call.getDetails();
            String phoneNumber = details.getHandle().getSchemeSpecificPart();
            //判断IncallMainActivity是否在栈中存在
            boolean existMainActivity = ActivityStack.getInstance().isExistMainActivity(this, InCallMainActivity.class);
            if (existMainActivity) {   //页面已存在, 给页面发消息, 将之前页面关闭
                BaseEvent event = new BaseEvent();
                event.setWhat(BaseEvent.Type.INCALL_UPDATE_INCALL);
                EventBus.getDefault().post(event);

            }
            //部分手机杀进程后 无法在service中直接开启来电界面, 采用广播中开启页面来曲线救国
            Intent intent = new Intent("INCALL_NEW_INCALL");
            intent.putExtra(Intent.EXTRA_PHONE_NUMBER, phoneNumber);
            intent.putExtra(Intent.EXTRA_MIME_TYPES, callType);
            sendBroadcast(intent);

        }


    }

BrocastReceiver


class IncallBroadcastReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent?.action == "INCALL_NEW_INCALL") {
            val callType = intent.getSerializableExtra(Intent.EXTRA_MIME_TYPES)
            val phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER)
            ARouter.getInstance().build(UrlConfig.INCALL_MAIN_ACTIVITY)
                    .withSerializable(Intent.EXTRA_MIME_TYPES, callType)
                    .withString(Intent.EXTRA_PHONE_NUMBER, phoneNumber)
                    .withFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                    .navigation()
        }
    }

}

Manisfest

<receiver android:name=".receiver.IncallBroadcastReceiver">
          <intent-filter>
              <action android:name="INCALL_NEW_INCALL"/>
          </intent-filter>
      </receiver>

分析问题2

如果到上一步就结束了的话, 你的问题只修复一半, 可以试一试杀进程后使用手机的去电功能, 你会发现又没办法唤醒了!!! 肿么回事呢?
请注意观察call.getState() 去电状态

    @Override
    public void onCallAdded(Call call) {
        .....
        CallType callType = null;
        if (call.getState() == Call.STATE_RINGING) { //来电
            callType = CallType.CALL_IN;
        } else if (call.getState() == Call.STATE_CONNECTING) { //去电
            callType = CallType.CALL_OUT;
        }
}

问题解决2

其实 在杀进程状态下, call.getState()状态值偷偷发生了改变, 变为了Call.STATE_DIALING, 下面是官方给的注释~

    /**
     * The state of an outgoing {@code Call} when dialing the 
        remote number, but not yet connected.
     */
    public static final int STATE_DIALING = 1;

代码修复


    @Override
    public void onCallAdded(Call call) {
       .....
        CallType callType = null;
        if (call.getState() == Call.STATE_RINGING) { //来电
            callType = CallType.CALL_IN;
        } else if (call.getState() == Call.STATE_CONNECTING || call.getState() == Call.STATE_DIALING) { //去电
            callType = CallType.CALL_OUT;
        }

分析原因3

近期发现在小米手机上, 只要应用在后台, 即使不杀进程也无法打开来电页面

问题解决3

小米最近出了公告, 默认关闭应用在后台被打开的权限, 官方公告地址:http://www.miui.com/thread-24191279-1-1.html

image.png

要想解决问题只能用户手动打开这个权限或者申请加入小米的白名单中

联想手机

目前联想手机有个应用自启动功能, 第三方应用安装后默认为禁止, 会导致杀进程状态下 无法唤醒来电, android适配真是硬伤....那么多开发商,能不能做做统一啊, 我不要做android了,哭哭.....

喜讯通知, 我们的应用已经通过小米的白名单啦, 哈哈哈~~

Android8.0以上 应用在后台呆一会之后, 静态广播无法接收消息(但是杀进程是可以的)

解决方案: 把静态广播换成动态的就可以解决

上一篇 下一篇

猜你喜欢

热点阅读