稀土掘金 稀土掘金

Android拨打电话与获取通话记录

需求

在 app 中点击按钮拨打电话,电话接通后进行录音,电话挂断以后可保存录音文件并获取通话时长。

功能实现

本次使用 HBuilderX 创建的 uni-app 项目进行实现。

拨打电话

拨打电话有两种方式,一是 plus.device.dial() , 二是 href='tel:xxxxxxx'.

plus.device.dial()

这是 HTML5+的一个API,具体说明如图:

image.png

href='tel:xxxxxxx'

  1. 使用 a 标签
<a href="tel:xxxxxxx">拨打电话</a>
  1. js 操作
function callPhone() {
    let phoneNumber = document.getElementById('tel').value;
    window.location.href = 'tel:' + phoneNumber;
}

录音

本次并没有实现通话录音功能,了解到相关资料如下:

  • 使用 android.media.MediaRecorder
  • 由于隐私保护等问题,只能实现单边录音。(没有深入研究,是否如此待考证。)

获取通话记录

获取通话记录需要相关的权限,而且是动态权限。 在 manifest.json 中勾选: 1630461509(1).png

image.png 动态权限:

plus.android.requestPermissions(
    ['android.permission.READ_CALL_LOG', 'android.permission.WRITE_CALL_LOG',
        'android.permission.READ_SMS'
    ],
    function(e) {
        if (e.deniedAlways.length > 0) {
            //权限被永久拒绝  
            // 弹出提示框解释为何需要定位权限,引导用户打开设置页面开启 
            console.log('Always Denied!!! ' + e.deniedAlways.toString());
        }
        if (e.deniedPresent.length > 0) {
            //权限被临时拒绝  
            // 弹出提示框解释为何需要定位权限,可再次调用plus.android.requestPermissions申请权限  
            console.log('Present Denied!!! ' + e.deniedPresent.toString());
        }
        if (e.granted.length > 0) {
            //权限被允许  
            //调用依赖获取定位权限的代码  
            console.log('Granted!!! ' + e.granted.toString());
        }
    },
    function(e) {
        console.log('Request Permissions error:' + JSON.stringify(e));
    }
)

获取通话记录:

var CallLog = plus.android.importClass('android.provider.CallLog');
var Activity = plus.android.runtimeMainActivity();
var ContentResolver = plus.android.importClass('android.content.ContentResolver');
var resolver = Activity.getContentResolver();
plus.android.importClass(resolver);
var String = plus.android.importClass("java.lang.String");

var cs = resolver.query(CallLog.Calls.CONTENT_URI, null, null, null, CallLog.Calls
	.DEFAULT_SORT_ORDER);
plus.android.importClass(cs);

要实现电话挂断后自动获取通话记录,那就得监听通话状态,此处用到了 TelephonyManager,而且需要勾选以下权限:

1630461545(1).png

遇到的问题

  1. 监听状态的服务启动以后,在 onReceive 方法中, this 只能获取到 data 中定义的内容,对于 methods 中定义的 getCalllog 方法则会提示未定义,在 data 中定义一个变量然后在 getCalllog 方法中赋值。
  2. TYPE 错误。这个应该是由于权限问题引发的错误,打包或使用自定义基座运行可解决。

完整代码

<template>
    <view class="content">
        <view class="box">
            <input v-model="telNumber" type="tel" value="" />
        </view>
        <view class="box">
            <button type="primary" @click="dial">拨号</button>
        </view>

        <div>
            <h4>content======输出打印=======</h4>
            <div>{{phoneState}}</div>
            <div v-for="(item,index) in content">{{item.callTime + '与' + item.mobile + '通话' + item.talkTime + '秒'}}
            </div>
        </div>
    </view>
</template>

<script>
    export default {
        data() {
            return {
                telNumber: 'xxxxxx',
                content: [],
                phoneState: '',
                getCallLogFn: null,
            }
        },
        onLoad() {
            this.listenToCall();
        },
        methods: {
            // 拨号
            dial: function() {
                // #ifdef APP-PLUS
                this.callTime = new Date();
                plus.device.dial(this.telNumber, false);
                // #endif
            },
            listenToCall() {
                let _this = this;
                _this.getCalllog();
                let maintest = plus.android.runtimeMainActivity();
                let Contexttest = plus.android.importClass("android.content.Context");
                let telephonyManager = plus.android.importClass("android.telephony.TelephonyManager");
                let telManager = plus.android.runtimeMainActivity().getSystemService(Contexttest.TELEPHONY_SERVICE);


                /* let MediaRecorder = plus.android.importClass('android.media.MediaRecorder');
                let recorder = new MediaRecorder(); */
				
                let receiver = plus.android.implements('io.dcloud.android.content.BroadcastReceiver', {
                    onReceive: function(Contexttest, intent) {
                        plus.android.importClass(intent);
                        // console.log(intent.getAction());
                        // let telephonyManager = plus.android.importClass("android.telephony.TelephonyManager");
                        // let telephonyManager=plus.android.runtimeMainActivity().getSystemService(Contexttest.TELEPHONY_SERVICE);
                        let phonetype = telManager.getCallState();
                        let phoneNumber = intent.getStringExtra(telephonyManager.EXTRA_INCOMING_NUMBER);
                        console.log("phoneType:" + phonetype); //电话状态 0->空闲状态 1->振铃状态 2->通话存在
                        if (phonetype === 0) {
                            try {
                                    _this.phoneState = '空闲状态';
                                    /* recorder.stop();
                                    recorder.reset();
                                    recorder.release();
                                    recorder = null; */
                                    _this.getCallLogFn();
                            } catch (e) {
                                    console.log(e);
                            }
                        }
                        /* else if(phonetype === 2) {
                            try {
                                console.log('try')
                                recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                                recorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);
                                recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
                                recorder.setOutputFile("_doc/audio/record.amr");
                                recorder.prepare();
                                recorder.start();
                            } catch (e) {
                                console.log(e.message);
                            }
                        } */
                    }
                });
                let IntentFilter = plus.android.importClass('android.content.IntentFilter');
                let filter = new IntentFilter();
                filter.addAction(telephonyManager.ACTION_PHONE_STATE_CHANGED);
                maintest.registerReceiver(receiver, filter);
            },
            getCalllog() {
                this.getCallLogFn = () => {
                    this.content = [];
                    //#ifdef APP-PLUS
                    // 权限处理  
                    plus.android.requestPermissions(
                        ['android.permission.READ_CALL_LOG', 'android.permission.WRITE_CALL_LOG',
                                'android.permission.READ_SMS'
                        ],
                        function(e) {
                            if (e.deniedAlways.length > 0) {
                                //权限被永久拒绝  
                                // 弹出提示框解释为何需要定位权限,引导用户打开设置页面开启 
                                console.log('Always Denied!!! ' + e.deniedAlways.toString());
                            }
                            if (e.deniedPresent.length > 0) {
                                //权限被临时拒绝  
                                // 弹出提示框解释为何需要定位权限,可再次调用plus.android.requestPermissions申请权限  
                                console.log('Present Denied!!! ' + e.deniedPresent.toString());
                            }
                            if (e.granted.length > 0) {
                                //权限被允许  
                                //调用依赖获取定位权限的代码  
                                console.log('Granted!!! ' + e.granted.toString());
                            }
                        },
                        function(e) {
                            console.log('Request Permissions error:' + JSON.stringify(e));
                        }
                    )

                    // 获取通话记录的主体代码 顺序不能够乱
                    var CallLog = plus.android.importClass('android.provider.CallLog');
                    var Activity = plus.android.runtimeMainActivity();
                    var ContentResolver = plus.android.importClass('android.content.ContentResolver');
                    var resolver = Activity.getContentResolver();
                    plus.android.importClass(resolver);
                    var String = plus.android.importClass("java.lang.String");

                    var cs = resolver.query(CallLog.Calls.CONTENT_URI, null, null, null, CallLog.Calls.DEFAULT_SORT_ORDER);
                    plus.android.importClass(cs);

                    var count = 0; // 记录多少条 用于处理循环跳出

                    while (cs.moveToNext()) {
                        count++;
                        //号码
                        var number = cs.getString(cs.getColumnIndex(CallLog.Calls.NUMBER));
                        //呼叫类型
                        var type;
                        switch (parseInt(cs.getString(cs.getColumnIndex(CallLog.Calls.TYPE))))
                        // 判断通话类型
                        {
                            case CallLog.Calls.INCOMING_TYPE:
                                type = "呼入";
                                break;
                            case CallLog.Calls.OUTGOING_TYPE:
                                type = "呼出";
                                break;
                            case CallLog.Calls.MISSED_TYPE:
                                type = "未接";
                                break;
                            default:
                                type = "挂断";
                                break;
                        }
                        // 获取时间
                        var date = new Date(parseInt(
                                cs.getString(cs.getColumnIndexOrThrow(CallLog.Calls.DATE))));
                        // 联系人
                        var Name_Col = cs.getColumnIndexOrThrow(CallLog.Calls.CACHED_NAME);
                        var name = cs.getString(Name_Col);
                        // 号码归属地 返回:北京 联通
                        var numberLocation = cs.getString(
                                cs.getColumnIndex(CallLog.Calls.GEOCODED_LOCATION)
                        );
                        //通话时间,单位:s
                        var Duration_Col = cs.getColumnIndexOrThrow(CallLog.Calls.DURATION);
                        var duration = cs.getString(Duration_Col);

                        // 存入数组 
                        this.content.push({
                            name: name, // 联系人的姓名
                            mobile: number, // 联系人电话
                            numberLocation: numberLocation, // 号码的归属地
                            callTime: this.formatDate(date), // 呼入或呼出时间
                            talkTime: duration, // 通话时长
                            type: type
                        });
                        if (count > 0) {
                                break;
                        }
                    }
                }
                //#endif
            },
            // 毫秒转日期
            formatDate(now) {
                    const date = new Date(now)
                    var y = date.getFullYear() // 年份
                    var m = date.getMonth() + 1 // 月份,注意:js里的月要加1
                    var d = date.getDate() // 日
                    var h = date.getHours() // 小时
                    var min = date.getMinutes() // 分钟
                    var s = date.getSeconds() // 秒
                    return y + '-' + m + '-' + d + ' ' + h + ':' + min + ':' + s
            },
        }
    }
</script>

<style>
    .box {
            width: 100%;
            margin-top: 50rpx;
    }
</style>

其他

生成证书

登录 dev.dcloud.net.cn/ ,显示应用列表:

image.png 点击应用名称进入应用详情页,选择“应用证书管理”可生成证书:

image.png 证书生成很快的,不过生成后需要刷新才会显示“证书已生成”。

自定义基座

菜单栏选择 “运行” -> “运行到手机或模拟器” -> “制作自定义调试基座”,出现弹窗以后填写证书相关信息,选择“传统打包”,点击“打包”就可以了。 image.png

image.png

调试

手机通过 USB 连接电脑以后,点击“运行” -> “运行到手机或模拟器”,选择“自定义基座”,再选择运行设备就好了。由于手头没有安卓机就不截图了。

参考

别人写好的插件:获取通话记录 发短信 拨号

监听电话状态

哆哆女性网鹿泉建设网站蚂蚁庄园答案最新pos单一定要签名吗株洲seo专业培训成都网站定制设计解梦鞋子淘宝的seo是什么怎样起店名字大全江苏适合的药材种植周易生辰八字算几两命起什么团队名做酒水的商贸公司起个名字大全商丘虞城独院出售大全重庆优化网站方法郑州建设网站多少钱起名为13画的字驾校起什么名字猪宝宝起名忌甚么祝姓起姓名精灵宝可梦剑盾手游破解版悲伤的个性签名男生餐饮学校培训班安卓手机排行榜大鱼解梦给大师起名周易五行五行长沙企业网站制作感伤与伤感句子梦见车祸唐姓姑娘起名大全淀粉肠小王子日销售额涨超10倍罗斯否认插足凯特王妃婚姻不负春光新的一天从800个哈欠开始有个姐真把千机伞做出来了国产伟哥去年销售近13亿充个话费竟沦为间接洗钱工具重庆警方辟谣“男子杀人焚尸”男子给前妻转账 现任妻子起诉要回春分繁花正当时呼北高速交通事故已致14人死亡杨洋拄拐现身医院月嫂回应掌掴婴儿是在赶虫子男孩疑遭霸凌 家长讨说法被踢出群因自嘲式简历走红的教授更新简介网友建议重庆地铁不准乘客携带菜筐清明节放假3天调休1天郑州一火锅店爆改成麻辣烫店19岁小伙救下5人后溺亡 多方发声两大学生合买彩票中奖一人不认账张家界的山上“长”满了韩国人?单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#青海通报栏杆断裂小学生跌落住进ICU代拍被何赛飞拿着魔杖追着打315晚会后胖东来又人满为患了当地回应沈阳致3死车祸车主疑毒驾武汉大学樱花即将进入盛花期张立群任西安交通大学校长为江西彩礼“减负”的“试婚人”网友洛杉矶偶遇贾玲倪萍分享减重40斤方法男孩8年未见母亲被告知被遗忘小米汽车超级工厂正式揭幕周杰伦一审败诉网易特朗普谈“凯特王妃P图照”考生莫言也上北大硕士复试名单了妈妈回应孩子在校撞护栏坠楼恒大被罚41.75亿到底怎么缴男子持台球杆殴打2名女店员被抓校方回应护栏损坏小学生课间坠楼外国人感慨凌晨的中国很安全火箭最近9战8胜1负王树国3次鞠躬告别西交大师生房客欠租失踪 房东直发愁萧美琴窜访捷克 外交部回应山西省委原副书记商黎光被逮捕阿根廷将发行1万与2万面值的纸币英国王室又一合照被质疑P图男子被猫抓伤后确诊“猫抓病”

哆哆女性网 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化