Android 多端互动实现方案

网络发现

网络发现中有主控设备(一般是移动端)与被控设备(一般是TV或者PC端)两种角色。

方案一(局域网发现)

采用mDns(组播DNS)相对更独立灵活一些,Android原生有API(NSD)。

在Windows上需要应用自己集成mDns开发。

为防止主控设备与错误的被控设备绑定,采用随机码辅助选择。被控设备会一直显示一个连接码。

在异构网络拓扑中,因为组播转发受限,该方案不可行,需要下面两个辅助方案。

Android NSD 使用:

public class ServiceDiscovery {

    public interface IServiceListener {
        void onServiceFound(NsdServiceInfo serviceInfo);
        void onServiceLost(NsdServiceInfo serviceInfo);
    }

    private static final String TAG = "ServiceDiscovery";
    private final String mServerType = "_board._tcp.";

    private NsdManager mNsdManager = null;
    private NsdManager.DiscoveryListener mDiscoveryListener = null;
    private NsdManager.ResolveListener mResolveListener = null;
    private IServiceListener mServiceListener;

    ServiceDiscovery(Context context, IServiceListener mServiceListener) {
        this.mServiceListener = mServiceListener;
        mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
        mDiscoveryListener = new MyDiscoveryListener();
        mResolveListener = new MyResolveListener();
    }

    public void startDiscover() {
        mNsdManager.discoverServices(mServerType,
                NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
    }

    public void resoleServer(NsdServiceInfo nsdServiceInfo){
        mNsdManager.resolveService(nsdServiceInfo, mResolveListener);
    }

    private class MyResolveListener implements NsdManager.ResolveListener {
        @Override
        public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
        }
        @Override
        public void onServiceResolved(NsdServiceInfo serviceInfo) {
            Log.i(TAG, "resolution : " + serviceInfo.getServiceName()
                    + " \n host_from_server: " + serviceInfo.getHost() +
                    "\n port from server: " + serviceInfo.getPort());
            String hostAddress = serviceInfo.getHost().getHostAddress();
            Log.i(TAG, "hostAddress ip--> " + hostAddress );
            mServiceListener.onServiceFound(serviceInfo);
        }
    }

    private class MyDiscoveryListener implements NsdManager.DiscoveryListener {
        @Override
        public void onStartDiscoveryFailed(String serviceType, int errorCode) {
            Log.i(TAG, "onStartDiscoveryFailed--> " + serviceType + ":" + errorCode);
        }
        @Override
        public void onStopDiscoveryFailed(String serviceType, int errorCode) {
            Log.i(TAG, "onStopDiscoveryFailed--> " + serviceType + ":" + errorCode);
        }
        @Override
        public void onDiscoveryStarted(String serviceType) {
            Log.i(TAG, "onDiscoveryStarted--> " + serviceType );
        }
        @Override
        public void onDiscoveryStopped(String serviceType) {
            Log.i(TAG, "onDiscoveryStopped--> " + serviceType );
        }
        @Override
        public void onServiceFound(NsdServiceInfo serviceInfo) {//关键的回调方法
            Log.i(TAG, "onServiceFound Info:  " + serviceInfo);
            resoleServer(serviceInfo);
        }
        @Override
        public void onServiceLost(NsdServiceInfo serviceInfo) {
            Log.i(TAG, "onServiceLost--> " + serviceInfo);
            mServiceListener.onServiceLost(serviceInfo);
        }
    }
}

方案二(后台辅助)

用后台辅助设备绑定,被控设备向后台注册,后台负责维护设备编号与网络地址的对应关系,主控设备通过某种途径获取到设备编号,然后到后台查询其最新的地址。

被控设备的网络地址端口可能每次启动不一样,最新的地址会同步到后台。

为防止IP地址变化引起的冲突,被控设备需要增加校验机制(比如校验编号),拒绝信息不匹配的请求。

方案三(二维码辅助)

被控设备显示二维码,包含网络地址信息,主控设备通过扫码获取这些信息。

可选的,主控设备主动把设备编号推给被控设备,被控设备立即并且以后每次启动都用新的编号更新地址。

使用zxing-android-embedded,启动扫码:

                IntentIntegrator intentIntegrator = new IntentIntegrator(MainActivity.this);
                intentIntegrator.setCaptureActivity(CaptureActivity.class);
                intentIntegrator.setBeepEnabled(false);
                intentIntegrator.initiateScan();

获取结果:

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
            IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
            if (result != null) {
                Log.d(TAG, "", result.getContents());
            }
    }

服务请求

采用定制推送协议,基于HTTP。

主控设备能够通过被控设备的地址主动连接被控设备。主控设备可能处于NAT内网,被控设备如果反向连接,需要在路由器上配置端口映射,基于UPNP/IGD可以自动配置端口映射,Android平台Upnp实现一般基于Cling库。

为解决 NAT 网络穿透问题,多端互动传输协议的设计要尽量避免反向连接,减少对网络拓扑的依赖。比如:投屏功能实现中视频数据的传输需要支持推流模式。

猜你喜欢

转载自blog.csdn.net/luansxx/article/details/90045795