1、背景需求:业务需要接入视频审核功能,在PC 端发起视频通话,移动端显示通话界面点击接听后进行1对1视频通话。

2、解决方案:因为项目没有IM功能。只集成了极光消息推送(极光消息推送接入参考官方文档:https://docs.jiguang.cn//jpush/guideline/intro/),经过跟需求沟通,采用消息推送调起通话接听界面。再集成腾讯实时音视频SDK(具体集成方式参考官方文档:https://cloud.tencent.com/document/product/647)。最终实现类似微信1对1通话功能。

3、技术实现:
A:编写一个广播接收器,并且在 AndroidManifest中注册,这就是一个全局的广播接收器。应用退到后台或者应用进程被kill,只要极光的push进程是Live,就能接受到消息,启动通话接听界面。

/*** Created on 2018/3/29 16:19* @author baokang.jia* 极光推送广播接收器*/
public class JiGuangPushReceiver extends BroadcastReceiver {private static final String TAG = "JPushReceiver";@Overridepublic void onReceive(Context context, Intent intent) {Bundle bundle = intent.getExtras();if (bundle == null) {return;}//拿到锁屏管理者KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);if (km != null && km.isKeyguardLocked()) {   //为true就是锁屏状态下startLoginOrCallActivity(context,bundle);} else {if (JPushInterface.ACTION_REGISTRATION_ID.equals(intent.getAction())) {String regId = bundle.getString(JPushInterface.EXTRA_REGISTRATION_ID);LogUtil.d(TAG, "[MyReceiver] 接收Registration Id : " + regId);//send the Registration Id to yours server...} else if (JPushInterface.ACTION_MESSAGE_RECEIVED.equals(intent.getAction())) {LogUtil.d(TAG, "[MyReceiver] 接收到推送下来的自定义消息: " + bundle.getString(JPushInterface.EXTRA_MESSAGE));} else if (JPushInterface.ACTION_NOTIFICATION_RECEIVED.equals(intent.getAction())) {//接收到推送下来的通知//启动通话界面startLoginOrCallActivity(context, bundle);} else if (JPushInterface.ACTION_NOTIFICATION_OPENED.equals(intent.getAction())) {//点击通知栏//启动通话界面startLoginOrCallActivity(context, bundle);//清除所有状态的通知JPushInterface.clearAllNotifications(context);} else if (JPushInterface.ACTION_RICHPUSH_CALLBACK.equals(intent.getAction())) {LogUtil.d(TAG, "[MyReceiver] 用户收到到RICH PUSH CALLBACK: " + bundle.getString(JPushInterface.EXTRA_EXTRA));//在这里根据 JPushInterface.EXTRA_EXTRA 的内容处理代码,比如打开新的Activity, 打开一个网页等..}}}/*** 未登录跳转登录界面,* else 启动通话接听界面*/private void startLoginOrCallActivity(Context context, Bundle bundle) {//EXTRA_EXTRAString extras = bundle.getString(JPushInterface.EXTRA_EXTRA);String userID = SPUtil.getString(context, Constants.LOGIN_USER_ID);if (TextUtils.isEmpty(userID)) {//启动登录界面Intent intent = new Intent(context, LoginActivity.class);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);context.startActivity(intent);} else {//启动通话接听界面int notifyId = bundle.getInt(JPushInterface.EXTRA_NOTIFICATION_ID);if (!TextUtils.isEmpty(extras) && extras.contains("androidNotification extras key")){ReceiveTalkActivity.startReceiveTalkActivity(context, extras,notifyId);}}}}
//在AndroidManifest注册全局自定义广播接收器
<receiverandroid:name=".event.JiGuangP`在这里插入代码片`ushReceiver"android:enabled="true"android:exported="false"><intent-filter><action android:name="cn.jpush.android.intent.REGISTRATION" /> <!-- Required  用户注册SDK的intent --><action android:name="cn.jpush.android.intent.MESSAGE_RECEIVED" /> <!-- Required  用户接收SDK消息的intent --><action android:name="cn.jpush.android.intent.NOTIFICATION_RECEIVED" /> <!-- Required  用户接收SDK通知栏信息的intent --><action android:name="cn.jpush.android.intent.NOTIFICATION_OPENED" /> <!-- Required  用户打开自定义通知栏的intent --><action android:name="cn.jpush.android.intent.CONNECTION" /> <!-- 接收网络变化 连接/断开 since 1.6.3 --><category android:name="${PACKAGE_NAME}" /></intent-filter></receiver>

B:启动通话接听界面,启动接听界面后获取当前手机模式

AudioManager audio = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
//手机模式,振动,精英、响铃,更具不同模式振动或者响铃,具体可参考以下的实现代码。
//点击接听按钮后跳转腾讯视频通话界面
/*** Created on 2019/4/28 16:19* @author baokang.jia* 视频预审接听界面*/
public class ReceiveTalkActivity extends BaseActivity {private static String PUSH_MSG_KEY = "push_msg_key";private static String NOTIFICATION_ID_KEY = "notification_id_key";/*** 腾讯云注册分配的appId*/private int sdkAppId =/*** 检查运行时权限*/private boolean mCheckPermissionResult = false;private PushMsgBean mPushMsgBean;/*** 媒体播放*/private MediaPlayer mMediaPlayer;/*** 震动*/private Vibrator mVibrator;@Overrideprotected void onCreate(Bundle savedInstanceState) {Window window = getWindow();//悬浮窗WindowViewUtil.setWindowFloatAndScreenOn(window,this);super.onCreate(savedInstanceState);//初始化倒计时器initCountDownTimer();//请求权限requestMustPermission();initViews();//根据通知Id清除状态栏对应的通知JPushInterface.clearAllNotifications(this);//持续震动和响铃continuedVibratorAndMediaPlayer();}/*** 60秒后关闭activity*/private void initCountDownTimer() {long time = 30000;long countDownInterval = 1000;CountDownTimer downTimer = new CountDownTimer(time, countDownInterval) {@Overridepublic void onTick(long millisUntilFinished) {}@Overridepublic void onFinish() {finish();}};downTimer.start();}@Overrideprotected int getLayoutId() {return R.layout.activity_receive_talk;}@Overrideprotected boolean initToolbar() {return false;}@Overrideprotected void getIntent(Intent intent) {String pushMsg = getIntent().getStringExtra(PUSH_MSG_KEY);//notificationId = getIntent().getIntExtra(NOTIFICATION_ID_KEY, 0);parsePushMsg(pushMsg);}@Overrideprotected void initViews() {Button btnCancel = findViewById(R.id.btn_cancel_call);Button btnAnswer = findViewById(R.id.btn_answer_call);btnCancel.setOnClickListener(v ->{mVibrator.cancel();mMediaPlayer.stop();finish();});btnAnswer.setOnClickListener(v -> {mVibrator.cancel();mMediaPlayer.stop();if (mCheckPermissionResult) {Intent intent = new Intent(this, TRTCMainActivity.class);intent.putExtra("roomId", Integer.valueOf(mPushMsgBean.getRoomId()));intent.putExtra("userId", mPushMsgBean.getUserId());intent.putExtra("sdkAppId", sdkAppId);intent.putExtra("userSig", mPushMsgBean.getUserSig());startActivity(intent);finish();} else {ToastUtil.longToast("需要的权限被拒绝,无法开启视频审核");}});}/*** 持续响铃和震动*/private void continuedVibratorAndMediaPlayer() {//获取媒体播放器mMediaPlayer = new MediaPlayer();try {mMediaPlayer.setDataSource(this, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE));//这里我用的通知声音,还有其他的,大家可以点进去看mMediaPlayer.prepare();} catch (IOException e) {e.printStackTrace();}//取得震动服务的句柄mVibrator = (Vibrator)this. getSystemService(VIBRATOR_SERVICE);//获取当前手机模式AudioManager audio = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);if (audio != null) {switch (audio.getRingerMode()) {case AudioManager.RINGER_MODE_SILENT://静音//do sthbreak;case AudioManager.RINGER_MODE_NORMAL://响铃mMediaPlayer.start();mMediaPlayer.setLooping(true); //循环播放break;case AudioManager.RINGER_MODE_VIBRATE://震动//数组参数意义:第一个参数为等待指定时间后开始震动,//震动时间为第二个参数。后边的参数依次为等待震动和震动的时间//第二个参数为重复次数,-1为不重复,0为一直震动if (mVibrator != null) {mVibrator.vibrate( new long[]{1000,1000},0);}break;}}}private void parsePushMsg(String pushMsg) {if (!TextUtils.isEmpty(pushMsg)) {CustomerMsg customerMsg = GsonUtil.fromJson(pushMsg, CustomerMsg.class);String pushMsgContent = customerMsg.getPushMsgContent();pushMsgContent = pushMsgContent.replace("\\", "");LogUtil.d(Constants.LOG,"pushMsgContent="+pushMsgContent);mPushMsgBean = GsonUtil.fromJson(pushMsgContent, PushMsgBean.class);}}/*** 申请应用必须的权限*/private void requestMustPermission() {AndPermission.with(this).requestCode(Constants.REQUEST_CODE_PERMISSION).permission(Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.CAMERA,Manifest.permission.RECORD_AUDIO,Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.VIBRATE,Manifest.permission.DISABLE_KEYGUARD,Manifest.permission.WAKE_LOCK).rationale((requestCode, rationale) ->//再次申请被拒绝的权限AlertDialog.newBuilder(this).setTitle(R.string.title_dialog).setMessage(R.string.message_permission_failed).setPositiveButton(R.string.ok, (dialog, which) -> {dialog.cancel();rationale.resume();}).setNegativeButton(R.string.no, (dialog, which) -> {dialog.cancel();rationale.cancel();}).show()).callback(new PermissionListener() {@Overridepublic void onSucceed(int requestCode, @NonNull List<String> grantPermissions) {mCheckPermissionResult = true;}@Overridepublic void onFailed(int requestCode, @NonNull List<String> deniedPermissions) {mCheckPermissionResult = false;}}).start();}/*** 界面未销毁,启动此界面时回调*/@Overrideprotected void onNewIntent(Intent intent) {super.onNewIntent(intent);String pushMsg = intent.getStringExtra(PUSH_MSG_KEY);//notificationId = intent.getIntExtra(NOTIFICATION_ID_KEY, 0);parsePushMsg(pushMsg);}/*** 提供给外部调用启动接听界面的activity** @param cex      上下文对象* @param pushMsg  消息内容* @param notifyId 通知id*/public static void startReceiveTalkActivity(Context cex, String pushMsg, int notifyId) {Intent calIntent = new Intent(cex, ReceiveTalkActivity.class);//携带数据calIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);calIntent.putExtra(PUSH_MSG_KEY, pushMsg);calIntent.putExtra(NOTIFICATION_ID_KEY, notifyId);cex.startActivity(calIntent);}@Overrideprotected void onDestroy() {super.onDestroy();mMediaPlayer.stop();mVibrator.cancel();}
}//注册ReceiveTalkActivity, android:launchMode="singleTask"
<activity android:name=".trtc.view.ReceiveTalkActivity"android:launchMode="singleTask"android:screenOrientation="portrait"/>

总结:项目中考虑时间和成本问题。没有接入IM功能。消息推送不可靠,极光的push进程被杀,是收不到消息。当打开app后,会蹦出很多通知。这只是简易的实现了在pc调起移动端进行视频通话。这有很多因素是没有考虑进去的,在此先记录下吧。

Android采用消息推送实现类似微信视频接听功能相关推荐

  1. 国内APP消息推送机制以及微信消息延迟问题剖析

    转自:https://club.huawei.com/thread-15878044-1-1.html 一.前言 随着安卓手机以及QQ/微信/支付宝/滴滴出行/美图外卖等一大批移动通信/移动消费应用的 ...

  2. Android端消息推送总结:实现原理、心跳保活、遇到的问题等

    前言 最近研究Android推送的实现, 研究了两天一夜, 有了一点收获, 写下来既为了分享, 也为了吐槽. 需要说明的是有些东西偏底层硬件和通信行业, 我对这些一窍不通, 只能说说自己的理解. 为什 ...

  3. 2015最新最全 Android 谷歌消息推送GCM 详细使用教程

    因为项目是非大陆的手机项目,所以当要使用到消息推送的时候,百度了一下,国内的消息方案可以是: 1.百度云推送.也确实很快就可以搭建客户端和服务端,加载他的sdk,大概花了半个小时,就可以在手机端收到推 ...

  4. VLC播放器Demo(录像,截图等功能),Android播放器Demo可二次开发。ffmpeg-Kit (录像,截图,合流播放,合流推送,等一些列视频操作功能),可二次开发。

    VLC播放器Demo(录像,截图等功能),可二次开发. ffmpeg-Kit (录像,截图,合流播放,合流推送,等一些列视频操作功能),可二次开发. 如果帮助的到了您,请您不要吝啬你的Star,先谢谢 ...

  5. android热门消息推送横向测评![转]

    关于这个话题,已经不是什么新鲜事了.对于大多数中小型公司一般都是选择第三方的服务来实现.但是现在已经有很多提供推送服务的公司和产品,如何选择一个适合自己项目的服务呢?它们之间都有什么差别?在此为大家做 ...

  6. android热门消息推送横向测评!

    关于这个话题,已经不是什么新鲜事了.对于大多数中小型公司一般都是选择第三方的服务来实现.但是现在已经有很多提供推送服务的公司和产品,如何选择一个适合自己项目的服务呢?它们之间都有什么差别?在此为大家做 ...

  7. Android 生态消息推送平台介绍

    一.手机厂商平台 华为消息推送服务 华为推送(Push)是为开发者提供的消息推送平台,建立了从云端到手机端的消息推送通道,使应用可以将最新信息及时通知用户,从而构筑良好的用户关系,提升用户的感知和活跃 ...

  8. java集成极光推送实现Android的消息推送

    1.极光推送的思路就是,每一个app都有一个AppKey和Master Secret,这两个值是唯一的,也就是用来标识App的唯一信息,具体怎么获取,去看极光推送官网文档,这里就不在讲解.我们在极光开 ...

  9. Android之消息推送实现

    在开发Android和iPhone应用程序时,我们往往需要从服务器不定的向手机客户端即时推送各种通知消息,iPhone上已经有了比较简单的和完美的推送通知解决方案,可是Android平台上实现起来却相 ...

  10. Android App消息推送 实现原理

    https://www.jianshu.com/p/b61a49e0279f 1.消息推送的实质 实际上,是当服务器有新消息需推送给用户时,先发送给应用App,应用App再发送给用户 2. 作用 产品 ...

最新文章

  1. VS中遇到 _WIN32_WINNT not defined
  2. 实验四+149+肖雷
  3. 怎么将导出的sql文件再次导入到数据库?
  4. ECMAScript 6 入门
  5. ACE网络编程模式比较
  6. 详解 Linux环境中DHCP分配IP地址(实验详解)
  7. Matlab2017b配置C++/C/Fortan编译器的问题
  8. 算法设计思维导图(算法设计与分析第二版)
  9. 飞机订票系统- c语言课程设,C语言课程设计飞机订票系统设计
  10. 综合评价法之秩和比法(RSR)
  11. java pem 私钥_JAVA:如何使用密码保护将私钥保存在pem文件中
  12. 樊登读书会用事实说话读后感_用事实说话樊登读书笔记
  13. 京瓷4501i打印机扫描步骤_「硬件」如何使用打印机扫描文件传送到电脑本地?...
  14. 太阳方位角 matlab,太阳天顶角与太阳方位角计算软件V4.1及源码
  15. 略谈“10步天才(10 step)思维模型”
  16. Walking Robot Simulation
  17. 解决:uni-app 图片加载不出来
  18. BPEL和XPDL的区别
  19. Android 项目必备(八)--> APP 的开发流程
  20. 一对一视频直播源码|手机视频直播平台android源码/可打包视频直播

热门文章

  1. Java多线程系列--“JUC集合”10之 ConcurrentLinkedQueue
  2. word文档左侧没有显示文档的目录
  3. TMS320F28035 中断中使用DINT,无法关闭中断的原因
  4. Yet Another Crosses Problem
  5. 不小心隐藏IDEA的main menu,让它恢复显示的解决方法
  6. JAVA实现Excel照相机功能_用Excel照相机功能在Excel中显示和调用图片的方法
  7. linux的进程rl,linux 进程 rl是什么状态
  8. Java拿到前一天的零点零分
  9. 为程序员爆肝整理的防治脱发大集锦
  10. 计算机顶级会议Rankings 英文投稿的一点经验