wifi direct 서비스 개발하기
샘플 프로젝트 : https://github.com/sunsoopark/Android_Wifi_direct_filetransfer
1. 개요
와이파이 다이렉트(Wi-Fi Direct)는 wifi기기간 접속을 지원하는 AP를 거치지 않고 기기간 직접접으로 통신하는 것을 말한다.안드로이드에서는 4.0(api 14) 이후부터 지원하고 있다. 관련 api를 이용할 경우 기기간 연결만 해줄뿐 데이터의 전송등의 작업은 소켓을 이용한 네트워크 통신프로그램을 구현 해야함
2. 주요 사용 패키지
android.net.wifi.p2p.WifiP2pManager3. 필요 퍼미션
Wifi p2p 기능을 사용하기 위한 기본적인 퍼미션<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
소켓 통신 위한 퍼미션
<uses-permission android:name="android.permission.INTERNET"/>
4. 연결 단계
위와같은 단계로 피어간에 연결이 이루어 지며 검색 방법에는 서비스로 검색하는 것과 단말을 검색하는 것 2가지로 나눌 수 있다. 서비스로 검색하는 것은 api 16이상부터 가능하다.
검색시 두 단말 모두 discover 해야 상호간에 확인 가능 하다.
5. 개발 단계별 설명
가. p2p 서비스 객체 초기화
다음과 같이 wifip2p 서비스 객체를 생성하고 채널 객체를 초기화 한다.
WifiP2pManager mWifiP2pManager = (WifiP2pManager) mContext.getSystemService(Context.WIFI_P2P_SERVICE);
WifiP2PManager.Channel p2pChannel = mWifiP2pManager.initialize(mContext, mContext.getMainLooper(), null);나. 피어 검색
검색관련 메소드의 콜백 결과값은 단순히 안드로이드 프레임워크에 해당 요청을 전송했다는 의미임, 해당 요청에 대한 결과를 알고 싶다면 브로드캐스트 리시버를 등록해야 함
해당 브로드 캐스트에 대한 액션은 다음과 같음
[Wi-Fi P2P 활성화시]
(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
[ 연결가능한 피어 목록이 변경시(requestPeers() 구현)]
WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
[ Wi-Fi P2P 연결상태(1:N연결을 위해 여기서 requestConnectionInfo() 호출 하도록 구현)]
WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
[ 현재 단말 상태정보]
(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
1)단말 검색
WifiP2pManager 클래스의 discoverPeers 메소드 호출
mWifiP2pManager.discoverPeers(p2pChannel, new WifiP2pManager.ActionListener() { @Override public void onSuccess() { Log.i(TAG, "discover success"); } @Override public void onFailure(int reason) { Log.i(TAG, "discover fail >>" + reason); } });이후 피어가 검색되면 등록한 브로드캐스트 리시버로 인텐트 전달됨
BroadcastReceiver wifiP2PReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) { int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
if (state == -1) return;
if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) { Log.i(TAG, "WIFI_P2P_STATE_ENABLED");
requestPeers(); } else { Log.i(TAG, "WIFI_P2P_STATE_DISABLED"); } } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) { Log.i(TAG, "WIFI_P2P_PEERS_CHANGED_ACTION"); //do request peer
requestPeers();
NetworkInfo netInfo = (NetworkInfo) intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO); if (netInfo != null && netInfo.isConnected()) { Log.i(TAG, "device connected:: " + netInfo.isConnected());
mWifiP2pManager.requestConnectionInfo(p2pChannel, new WifiP2pManager.ConnectionInfoListener() { @Override
public void onConnectionInfoAvailable(WifiP2pInfo info) { mWifiP2pInfo = info; } }); } } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) { Log.i(TAG, "WIFI_P2P_CONNECTION_CHANGED_ACTION");
} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) { Log.i(TAG, "WIFI_P2P_THIS_DEVICE_CHANGED_ACTION"); } } };
2) 서비스 검색
가. 서비스 등록
Map record = new HashMap<String, String>();
record.put("listenport", Constants.FILE_SERVICE_PORT);
record.put("buddyname", "John Doe" + (int) (Math.random() * 1000));record.put("available", "visible"); WifiP2pServiceInfo info = WifiP2pDnsSdServiceInfo.newInstance("_tester", "ip_tcp", record);
mWifiP2pManager.addLocalService(p2pChannel, info, new WifiP2pManager.ActionListener() { @Override
public void onSuccess() { mCallback.onSucess("addLocalService success"); Log.v(TAG, "success"); } @Override
public void onFailure(int reason) { mCallback.onFailure(reason); Log.v(TAG, "fail ::" + reason); } });나. 서비스 요청
WifiP2pManager.DnsSdTxtRecordListener txtListener = new WifiP2pManager.DnsSdTxtRecordListener() { @Override/* Callback includes: * fullDomain: full domain name: e.g "printer._ipp._tcp.local." * record: TXT record dta as a map of key/value pairs. * device: The device running the advertised service. */ public void onDnsSdTxtRecordAvailable( String fullDomain, Map record, WifiP2pDevice device) { Log.d(TAG, "DnsSdTxtRecord available -" + record.toString());
buddies.put(device.deviceAddress, (String) record.get("buddyname")); } }; WifiP2pManager.DnsSdServiceResponseListener serviceResponseListener =
new WifiP2pManager.DnsSdServiceResponseListener() { @Override
public void onDnsSdServiceAvailable(String instanceName, String registrationType, WifiP2pDevice srcDevice) { Log.d(TAG, "service res available [" + instanceName + "/type:" + registrationType); } };
mWifiP2pManager.setDnsSdResponseListeners(p2pChannel, serviceResponseListener, txtListener);
WifiP2pDnsSdServiceRequest serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();//서비스 검색 요청 추가
mWifiP2pManager.addServiceRequest(p2pChannel, serviceRequest, new WifiP2pManager.ActionListener() { @Override
public void onSuccess() { Log.v(TAG, "sevice success"); } @Override
public void onFailure(int code) { // Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY
Log.v(TAG, "sevice fail :: " + code); } });//서비스 검색
mWifiP2pManager.discoverServices(p2pChannel, new WifiP2pManager.ActionListener() { @Override public void onSuccess() { } @Override public void onFailure(int reason) { } });
3. 피어간 연결
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
config.wps.setup = WpsInfo.PBC; mWifiP2pManager.connect(p2pChannel, config, new WifiP2pManager.ActionListener() { @Override public void onSuccess() { Log.v(TAG, "connect success"); requestPeers(); } @Override public void onFailure(int reason) { Log.v(TAG, "connect fail >>" + reason); } });
이후의 동작은 서버/클라이언트로 소켓 연결하여 구현 하면 됨
1. 서버는 원하는 포트를 열고 클라이언트의 접속을 기다림
welcomeSocket = new ServerSocket(8988); while (true) { socket = welcomeSocket.accept(); if(socket.isConnected()){ break; } }2. 클라이언트는 WifiP2pInfo객체에서 group owner의 ip주소를 가져와서 연결,
Wifip2pinfo 객체는 wifip2pManager 객체의 requestConnectionInfo() 호출하여 얻음
WifiP2pInfo wifiInfo = (WifiP2pInfo) intent.getParcelableExtra("host");InetAddress targetIP = null; if (!wifiInfo.isGroupOwner) { targetIP = wifiInfo.groupOwnerAddress;} try { socket.bind(null); socket.connect(new InetSocketAddress(targetIP, 8988), 5000);
}
댓글 없음:
댓글 쓰기