android投屏技术🔥🔥:发现设备代码实现

1字数 898阅读 16515
cover

关于 android 投屏技术系列:
一、知识概念

这章主要讲一些基本概念, 那些 DLNA 类库都是基于这些概念来做的,了解这些概念能帮助你理清思路,同时可以提升开发效率,遇到问题也能有个解决问题的清晰思路。

二、手机与tv对接

这部分是通过Cling DLNA类库来实现发现设备的。
内容包括:

  1. 抽出发现设备所需接口
  2. 发现设备步骤的实现
  3. 原理的分析

三、手机与tv通信

这部分也是通过Cling DLNA类库来实现手机对tv的控制。
内容包括:

  1. 控制设备步骤
  2. 控制设备代码实现
  3. 手机如何控制tv
  4. tv将自己的信息如何通知手机
  5. 原理的分析

前言

上篇文章,我们聊了投屏技术所需的协议和概念。今天我们来实际操作。


神操作

何为发现设备?
android 手机投屏到 tv盒子 上,首先你要让 tv盒子 跟你的手机在同一个局域网中,然后要让手机能搜索到当前局域网内所有支持投屏的设备(如:tv盒子)这个过程 就是发现设备。

噢了~ 这篇文章分两部分:

  • 第一部分是 Cling库 的使用以及里面基本概念。
  • 第二部分是 Cling库 发现设备部分的源码分析。
action

行动前,先分析一下 我们的需求:

  1. 手机 & tv盒子 都连上局域网
  2. 手机需要随时监听局域网中支持投屏设备的出现
  3. 手机跟支持投屏的 tv盒子 建立连接

首先,看 Cling库 的介绍:

Cling

它主要由 core 和 support 两个部分构成。

  • core: 包含了发现设备部分
  • support: 包含的是控制设备部分

今天我们要用到的是 core 部分。
一切准备就绪,大哥,我们开始实现发现设备功能好不好?
不好也得好,就是这么任性,略略略

打我啊

发现设备功能实现

首先我们要在 manifest 里加上以下权限(网络相关权限):

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>

在 Cling 中针对 android 定义了一个 Service 来操作------>AndroidUpnpServiceImpl
它有以下方法:

public UpnpServiceConfiguration getConfiguration();

public ControlPoint getControlPoint();

public ProtocolFactory getProtocolFactory();

public Registry getRegistry();

public Router getRouter();

public IBinder onBind(Intent intent);
  
public void onDestroy();

不懂没关系。
现在你只需要知道:

  • ControlPoint getControlPoint() 获取到控制点,通过控制点执行 search() 方法就可以发现设备了
  • 然后就是 我们可以根据需求在 activity 里 bind 或者 unbind AndroidUpnpServiceImpl 这个 Service

接下来我们要在 manifest 里面定义这个 Service

<service android:name="org.fourthline.cling.android.AndroidUpnpServiceImpl"/>

下面是 activity:

public class BrowserActivity extends ListActivity {

    private ArrayAdapter<DeviceDisplay> listAdapter;

   // 监听设备发现,当一个新设备出现在网络时,会回调它
    private BrowseRegistryListener registryListener = new BrowseRegistryListener();

    private AndroidUpnpService upnpService;

    private ServiceConnection serviceConnection = new ServiceConnection() {

        public void onServiceConnected(ComponentName className, IBinder service) {
            upnpService = (AndroidUpnpService) service;

            listAdapter.clear();

            // 添加监听
            upnpService.getRegistry().addListener(registryListener);

            // 添加已知的设备
            for (Device device : upnpService.getRegistry().getDevices()) {
                registryListener.deviceAdded(device);
            }

            // 搜索所有的设备
            upnpService.getControlPoint().search();
        }

        public void onServiceDisconnected(ComponentName className) {
            upnpService = null;
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        listAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1);
        setListAdapter(listAdapter);

        // This will start the UPnP service if it wasn't already started
        getApplicationContext().bindService(
            new Intent(this, AndroidUpnpServiceImpl.class),
            serviceConnection,
            Context.BIND_AUTO_CREATE
        );
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (upnpService != null) {
            upnpService.getRegistry().removeListener(registryListener);
        }
        // This will stop the UPnP service if nobody else is bound to it
        getApplicationContext().unbindService(serviceConnection);
    }
    // ...
}

这段代码就实现了两个功能:

  1. upnpService.getControlPoint().search(); 实现发现设备
  2. BrowseRegistryListener registryListener;
    upnpService.getRegistry().addListener(registryListener);
    实现了发现设备监听

其实 就这么简单,<b>但</b>搜索到的 并不是我们想要的结果,我要筛选到支持投屏渲染的设备:

    public static final DeviceType DMR_DEVICE_TYPE = new UDADeviceType("MediaRenderer");

    /**
     * 获取支持投屏的设备
     *
     * @return  设备列表
     */
    @Override
    @Nullable
    public Collection<Device> getDmrDevices() {
        if (Utils.isNull(mUpnpService))
            return null;

        Collection<Device> devices = upnpService.getRegistry().getDevices(DMR_DEVICE_TYPE);

        return devices;
    }

噢了~~

点击查看详细代码

(* 详细代码里 做了一些封装)

下面我们进入正式环节-源码分析:
由于文章太长,我分开到下篇文章

android投屏技术:发现设备源码分析

推荐阅读更多精彩内容