태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.
2019.01.28 11:30


[android] Google Play Service: Nearby Connections API



https://code.tutsplus.com/tutorials/google-play-services-using-the-nearby-connections-api--cms-24534


accept connections, acceptConnectionRequest, ACCESS_NETWORK_STATE, Advertising, disconnectFromEndpoint, google play service, GoogleApiClient, GPS, LAN, manifest, nearbu connections api, nearby connection use case, onMessageReceived, permission, rejectConnectionRequest, sendConnectionRequest, sendReliableMessage, sendUnreliableMessage, SERVICE_ID, startadvertising, stopAdvertising, stopAllEndPoints, stopDiscovery, TCP, UDP, [android] Google Play Service: Nearby Connections API



-

Google Play Service(이하 G.P.S) 에 있는 Nearby Connections API 를 이용하면,

LAN ( Local Area Network ) 를 이용해 App 을 host 로 작동시키면서 여러개의 device 를 해당 host 에 연결시킬 수 있다.


Use case 는 phone 을 android TV 에 연결해서 control 을 한다던지, Multi user 를 연결해서 game 을 한다던지 할 수 있겠다.



1. Project Setup


-

gradle compile 추가

compile 'com.google.android.gms:play-services:7.5.0’



-

LAN 을 사용하기 위해서 아래 permission 이 필요하다.

MOS 의 runtime permission 은 알아서 잘 대응 할 수 있을 것이라 믿는다.

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />



-

연결을 위한 일종의 Key 인 SERVICE_ID 가 필요하다.

이 녀석을 manifest 의 application 에 정의해야 한다.

<meta-data android:name="com.google.android.gms.nearby.connection.SERVICE_ID" android:value="@string/service_id" />



-

Nearby Connections API 뿐만 아니라 G.P.S. API 를 사용하기 위해서는 대부분 GoogleApiClient 연결이 필요하다.

( 최근 Lib 들은 이것을 잘 hide 하는 편이지만, 해당 article 이 조금 오래된 녀석이라.. )

mGoogleApiClient = new GoogleApiClient.Builder( this )
        .addConnectionCallbacks( this ) // GoogleApiClient.ConnectionCallback
        .addOnConnectionFailedListener( this ) // GoogleApiClient.OnConnectionFailedListener
        .addApi( Nearby.CONNECTIONS_API )
        .build();


보통 onStart 에서 client 에 connect 를 하고 onStop 에서 client 를 disconnect 한다

@Override
protected void onStart() {
    super.onStart();
    mGoogleApiClient.connect();
}
 
@Override
protected void onStop() {
    super.onStop();
    if( mGoogleApiClient != null && mGoogleApiClient.isConnected() ) {
        mGoogleApiClient.disconnect();
    }
}





2. Advertising and Accepting Connections


-

Advertising 은 host 가 “나 여기있으니 연결할 사람 연결해요” 라고 광고하는 것이다.

advertising 시작은 Nearby.Connections.startAdvertising 을 호출해주면 된다

// LAN 만 사용한다 private static int[] NETWORK_TYPES = {ConnectivityManager.TYPE_WIFI, ConnectivityManager.TYPE_ETHERNET }; private boolean isConnectedToNetwork() { ConnectivityManager connManager = (ConnectivityManager) getSystemService( Context.CONNECTIVITY_SERVICE ); for( int networkType : NETWORK_TYPES ) { NetworkInfo info = connManager.getNetworkInfo( networkType ); if( info != null && info.isConnectedOrConnecting() ) { return true; } } return false; } private void advertise() { if( !isConnectedToNetwork() ) return; String name = "Nearby Advertising”; // 마지막 this 는 Connections.ConnectionRequestListener, Nearby.Connections.startAdvertising( mGoogleApiClient, name, null, CONNECTION_TIME_OUT, this ) .setResultCallback( new ResultCallback<Connections.StartAdvertisingResult>() { @Override public void onResult( Connections.StartAdvertisingResult result ) { if( result.getStatus().isSuccess() ) { // Advertising success } } }); }


-

host 에 연결하려는 시도를 받으면 아래 callback 이 불린다.

수락하려면 Nearby.Connections.acceptConnectionRequest, 거절하려면 Nearby.Connections.rejectConnectionRequest 를 호출하면 된다.

// Connections.ConnectionRequestListener 의 callback
public void onConnectionRequest(final String remoteEndpointId, final String remoteDeviceId, final String remoteEndpointName, byte[] payload) {
    if( mIsHost ) {
        
        // 마지막 this 는 Connections.MessageListener,
        Nearby.Connections.acceptConnectionRequest( mGoogleApiClient, remoteEndpointId, payload, this ).setResultCallback(new ResultCallback<Status>() {
            @Override
            public void onResult(Status status) {
                if( status.isSuccess() ) {
                    if( !mRemotePeerEndpoints.contains( remoteEndpointId ) ) {
                        mRemotePeerEndpoints.add( remoteEndpointId );
                    }
 
                    mMessageAdapter.add(remoteDeviceId + " connected!");
                    mMessageAdapter.notifyDataSetChanged();
                    sendMessage(remoteDeviceId + " connected!");
 
                    mSendTextContainer.setVisibility( View.VISIBLE );
                }
            }
        });
    } else {
        Nearby.Connections.rejectConnectionRequest(mGoogleApiClient, remoteEndpointId );
    }
}






3. Discovery


-

Nearby.Connections.startDiscovery 를 호출하면 host 를 검색할 수 있다.

private void discover() {
    if( !isConnectedToNetwork() )
        return;
 
    String serviceId = getString( R.string.service_id );

    // 마지막 this 는 Connections.EndpointDiscoveryListener
    Nearby.Connections.startDiscovery(mGoogleApiClient, serviceId, 10000L, this).setResultCallback(new ResultCallback<Status>() {
                @Override
                public void onResult(Status status) {
                    if (status.isSuccess()) {
                        mStatusText.setText( "Discovering" );
                    } else {
                        Log.e( "TutsPlus", "Discovering failed: " + status.getStatusMessage() );
                    }
                }
            });
}



-

Host 를 찾으면 아래 Callback 이 불린다.

Nearby.Connections.sendConnectionRequest 를 호출해 연결을 시도한다.

// Connections.EndpointDiscoveryListener callback 중 하나
public void onEndpointFound(String endpointId, String deviceId, final String serviceId, String endpointName) {
    byte[] payload = null;

    // 마지막 this 는 Connections.MessageListener 이다
 
    Nearby.Connections.sendConnectionRequest( mGoogleApiClient, deviceId, endpointId, payload, new Connections.ConnectionResponseCallback() {
 
        @Override
        public void onConnectionResponse(String endpointId, Status status, byte[] bytes) {
            if( status.isSuccess() ) {
                mStatusText.setText( "Connected to: " + endpointId );
                Nearby.Connections.stopDiscovery(mGoogleApiClient, serviceId);
                mRemoteHostEndpoint = endpointId;
                mSendTextContainer.setVisibility(View.VISIBLE);
 
                if( !mIsHost ) {
                    mIsConnected = true;
                }
            } else {
                mStatusText.setText( "Connection to " + endpointId + " failed" );
                if( !mIsHost ) {
                    mIsConnected = false;
                }
            }
        }
    }, this );
}

연결 전에 host 가 advertising 을 그만둔 경우 onEndpointLost method 가 불리고,

에러로 인해 제대로 된 연결이 안 되었을 경우(disconnect 가 된 경우) onDisconnected method 가 불린다.





4. Sending Messages


-

Message 는 reliable 한 TCP 와 unreliable 한 UDP 가 있다.


Message 가 도착한 경우 onMessageReceived 가 불린다.

// Connections.MessageListener 의 callback
public void onMessageReceived(String endpointId, byte[] payload, boolean isReliable) {
    mMessageAdapter.add( new String( payload ) );
    mMessageAdapter.notifyDataSetChanged();
 
    if( mIsHost ) {
        sendMessage( new String( payload ) );
    }
} 



-

sendMessage 는 필자가 구현한 method 로 안쪽에서는 Nearby.Connections.sendReliableMessage 혹은 Nearby.Connections.sendUnreliableMessage 를 통해 메시지를 보낸다.


접속하는 device 들은 Nearby.Connections.getLocalDeviceId 를 통해 본인의 id 를 가져올 수 있다.

private void sendMessage( String message ) {
    if( mIsHost ) {
        Nearby.Connections.sendReliableMessage( mGoogleApiClient,
          mRemotePeerEndpoints,
          message.getBytes() );
         
        mMessageAdapter.add( message );
        mMessageAdapter.notifyDataSetChanged();
    } else {
        Nearby.Connections.sendReliableMessage( mGoogleApiClient,
          mRemoteHostEndpoint,
          ( Nearby.Connections.getLocalDeviceId( mGoogleApiClient ) + " says: " + message ).getBytes() );
    }
}




5. Disconnecting


-

host 에서는 Nearby.Connections.stopAdvertising 과 Nearby.Connections.stopAllEndPoints 를 통해 disconnect 하고,

peer 에서는 Nearby.Connections.stopDiscovery, Nearby.Connections.disconnectFromEndpoint 를 통해 disconnect 한다


private void disconnect() {
    if( !isConnectedToNetwork() )
        return;
 
    if( mIsHost ) {
        sendMessage( "Shutting down host" );
        Nearby.Connections.stopAdvertising( mGoogleApiClient );
        Nearby.Connections.stopAllEndpoints( mGoogleApiClient );
        mIsHost = false;
        mStatusText.setText( "Not connected" );
        mRemotePeerEndpoints.clear();
    } else {
        if( !mIsConnected || TextUtils.isEmpty( mRemoteHostEndpoint ) ) {
            Nearby.Connections.stopDiscovery( mGoogleApiClient, getString( R.string.service_id ) );
            return;
        }
 
        sendMessage( "Disconnecting" );
        Nearby.Connections.disconnectFromEndpoint( mGoogleApiClient, mRemoteHostEndpoint );
        mRemoteHostEndpoint = null;
        mStatusText.setText( "Disconnected" );
    }
 
    mIsConnected = false;
}



-

끝!




댓글을 달아 주세요


Posted by 돼지왕왕돼지