Android实现录屏直播(二)需求才是硬道理之产品功能调研
請尊重分享成果,轉(zhuǎn)載請注明出處,本文來自Coder包子哥,原文鏈接:http://blog.csdn.net/zxccxzzxz/article/details/54254244
Android實(shí)現(xiàn)錄屏直播(一)ScreenRecorder的簡單分析
Android實(shí)現(xiàn)錄屏直播(二)需求才是硬道理之產(chǎn)品功能調(diào)研
Android實(shí)現(xiàn)錄屏直播(三)MediaProjection + VirtualDisplay + librtmp + MediaCodec實(shí)現(xiàn)視頻編碼并推流到rtmp服務(wù)器
前面的Android實(shí)現(xiàn)錄屏直播(一)ScreenRecorder的簡單分析一文中我們對 ScreenRecorder 這個(gè)開源 Demo 中的實(shí)現(xiàn)機(jī)制大概有了了解,但在繼續(xù)寫這個(gè)系列文章的時(shí)候發(fā)現(xiàn)每一個(gè)細(xì)節(jié)都太緊密了,稍微不注意就會(huì)深入每個(gè)知識(shí)點(diǎn)的細(xì)節(jié)導(dǎo)致文章又臭又長還表述不清晰,于是我決定把這7天實(shí)現(xiàn)該功能的整個(gè)流程重新梳理一遍,按照我開發(fā)和研究學(xué)習(xí)的步驟來寫,大致過程如下:
產(chǎn)品功能調(diào)研
我們作為技術(shù)開發(fā)人員,任務(wù)下發(fā)的時(shí)候首先要與產(chǎn)品經(jīng)理進(jìn)行需求的深入了解,只有了解對方想要的是什么后我們功能實(shí)現(xiàn)才能達(dá)到他們最大的期望值。當(dāng)然一旦確定需求后把菜刀亮出來,然后就輕松愉快的寫代碼吧��。嗯,本次任務(wù)就是盡可能的還原Bilibili的錄屏直播功能,汗顏,無需設(shè)計(jì),無需討論,我自己研究吧,反正項(xiàng)目一直都是我一人開發(fā),也習(xí)慣了(PS: 盡管是Bilibili的忠實(shí)用戶,當(dāng)然不能在工作的時(shí)候看番劇啦),廢話不多說,瞄準(zhǔn)幾個(gè)功能:
- 直播懸浮窗
- 直播提示通知欄
- 錄屏直播的實(shí)現(xiàn)機(jī)制
直播懸浮窗
說起懸浮窗不得不感謝郭神的博客?Android桌面懸浮窗效果實(shí)現(xiàn),仿360手機(jī)衛(wèi)士懸浮窗效果,就是懶直接拿來修修改改就行(郭神別打我~),實(shí)現(xiàn)效果如圖
懸浮窗包含一個(gè)自定義的View(繼承自FrameLayout)、服務(wù)和自定義WindowManager,更多細(xì)節(jié)請見源碼,代碼就不貼出來了,太占地方。值得注意的是,這里的懸浮窗我添加了一個(gè)彈幕顯示的ListView面板用于顯示用戶的發(fā)言。
直播提示通知欄
由于直接錄制桌面涉及到用戶的個(gè)人隱私問題,如果沒有一個(gè)標(biāo)識(shí)讓用戶看著那問題就麻煩了(親測過通過這種錄屏方式可以捕獲桌面所有的內(nèi)容,無論是鍵盤輸入狀態(tài)、攝像頭拍照攝像及輸入銀行卡密碼等等),所以Android系統(tǒng)雖然會(huì)提示需要進(jìn)行屏幕錄像,但還是有一定的風(fēng)險(xiǎn)!通知欄屬于常駐類型,內(nèi)容如下:
通知欄的實(shí)現(xiàn)
先看看下面這個(gè)服務(wù)類,主要功能就是開啟通知并創(chuàng)建懸浮窗兩個(gè)功能,注意創(chuàng)建懸浮窗時(shí)判斷當(dāng)前設(shè)備是否為我們的APP授權(quán)了懸浮窗權(quán)限這個(gè)功能我還沒有來得及實(shí)現(xiàn),小米、魅族華為等系統(tǒng)需要手動(dòng)去APP設(shè)置中授權(quán),之后有時(shí)間再補(bǔ)上。如需此服務(wù)與Activity之間有通信機(jī)制的話,還需要自定義Binder,在啟動(dòng)服務(wù)的Activity中通過bindService()與ServiceConnection來實(shí)現(xiàn)數(shù)據(jù)的傳遞,這里先挖一個(gè)坑,后續(xù)我完善功能后再回來填上。
import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.os.Binder; import android.os.Handler; import android.support.v4.app.NotificationCompat; import android.app.Service; import android.content.Intent; import android.os.IBinder;public class ScreenRecordListenerService extends Service {private static final String TAG = "ScreenRecordListenerService, ";private static final int PENDING_REQUEST_CODE = 0x01;private static final int NOTIFICATION_ID = 3;private NotificationManager mNotificationManager;private NotificationCompat.Builder builder;private Handler handler = new Handler();@Overridepublic void onCreate() {super.onCreate();initNotification();}@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// 當(dāng)前界面是桌面,且沒有懸浮窗顯示,則創(chuàng)建懸浮窗。if (!MyWindowManager.isWindowShowing()) {handler.post(new Runnable() {@Overridepublic void run() {MyWindowManager.createSmallWindow(getApplicationContext());}});}return super.onStartCommand(intent, flags, startId);}private void initNotification() {builder = new NotificationCompat.Builder(this).setSmallIcon(R.drawable.ic_launcher).setContentTitle(getResources().getString(R.string.app_name)).setContentText("您正在錄制視頻內(nèi)容哦").setOngoing(true).setDefaults(Notification.DEFAULT_VIBRATE);Intent backIntent = new Intent(this, RecordActivityV2.class);PendingIntent pendingIntent = PendingIntent.getActivity(this, PENDING_REQUEST_CODE, backIntent, PendingIntent.FLAG_UPDATE_CURRENT);builder.setContentIntent(pendingIntent);mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);mNotificationManager.notify(NOTIFICATION_ID, builder.build());}@Overridepublic void onDestroy() {super.onDestroy();if (mNotificationManager != null) {mNotificationManager.cancel(NOTIFICATION_ID);}MyWindowManager.removeSmallWindow(getApplicationContext());} }上面的代碼我們可以看出服務(wù)啟動(dòng)后進(jìn)行了Notification的初始化,我這里按照Bilibili的樣式去實(shí)現(xiàn)的。在Activity中當(dāng)啟動(dòng)直播時(shí),Bilibili是通過moveTaskToBack(true)直接回到桌面的,所以我猜想開啟通知欄和懸浮窗服務(wù)應(yīng)該是在Activity生命周期的onStop()啟動(dòng)和onResume()關(guān)閉,當(dāng)然這些都是業(yè)務(wù)邏輯可自己定義。
@Override protected void onResume() {super.onResume();if (isRecording) stopScreenRecordService(); }@Override protected void onStop() {super.onStop();if (isRecording) startScreenRecordService(); }private void startScreenRecordService() {if (mRecorder != null && mRecorder.getStatus()) {Intent runningServiceIT = new Intent(this, ScreenRecordListenerService.class);// bindService(runningServiceIT, connection, BIND_AUTO_CREATE); startService(runningServiceIT);} }private void stopScreenRecordService() {Intent runningServiceIT = new Intent(this, ScreenRecordListenerService.class);stopService(runningServiceIT);if (mRecorder != null && mRecorder.getStatus()) {Toast.makeText(this, "現(xiàn)在正在進(jìn)行錄屏直播哦", Toast.LENGTH_SHORT).show();} }最后別忘了在AndroidManifest.xml中進(jìn)行Service的注冊和對懸浮窗的授權(quán)。
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <application <serviceandroid:name=".service.ScreenRecordListenerService"android:enabled="true"android:exported="false" /> </application>關(guān)于懸浮窗與通知欄差不多就介紹到這里了,更多細(xì)節(jié)請查看源碼,本Demo源碼都是基于上篇博客提到的ScreenRecorder實(shí)現(xiàn)的。
我們來看看最終效果吧:
錄屏直播的實(shí)現(xiàn)機(jī)制
使用MediaProjection與VirtualDisplay等Android 5.0以上的API實(shí)現(xiàn)的,在此就不多說了,請看上篇博客吧。
尾語
果然還是有個(gè)提綱要好下筆的多,至少知道寫些什么。因?yàn)樽罱恼聦懙亩加悬c(diǎn)趕,有疑問的朋友還請留言指正!接下來準(zhǔn)備寫一下MediaProjection 實(shí)現(xiàn)錄屏中 MediaCodec 的詳細(xì)用法,至于反編譯Bilibili的過程就不寫了,反編譯為的是參考別人的思路,并不是為了做代碼小偷,這點(diǎn)職業(yè)操守還是有的,如果說業(yè)務(wù)上有盜竊之意請出門左轉(zhuǎn)找我們的產(chǎn)品經(jīng)理,我是無辜的碼農(nóng)[笑]。之后會(huì)在別的文章中提及一下我個(gè)人使用反編譯時(shí)的一些心得和小技巧吧。別的主題都還需要花些時(shí)間再看看,畢竟都是工作時(shí)候囫圇吞棗接觸的,理論知識(shí)可不能瞎糊弄。
Demo源碼
Demo源碼都在我的GitHub倉庫中,有需要的朋友可以去 clone 或 fork,如對您有幫助還請給個(gè)Star,十分感謝~
參考文檔
- Android桌面懸浮窗效果實(shí)現(xiàn),仿360手機(jī)衛(wèi)士懸浮窗效果
- Android Notification
- Android面試一天一題(1Day)IntentService作用是什么
- Android–通知之Notification
總結(jié)
以上是生活随笔為你收集整理的Android实现录屏直播(二)需求才是硬道理之产品功能调研的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SpringBoot充电桩平台
- 下一篇: 图像差分的方法