บทความนี้สาธิตการใช้ WiFi Direct (Wi-Fi P2P) ใน Android เพื่อเชื่อมต่ออุปกรณ์โดยตรงโดยไม่ต้องมี Access Point (Router) ใช้ WifiP2pManager และ BroadcastReceiver
🔧 ข้อกำหนดเบื้องต้น
- Android 4.0+ (API 14) รองรับ WiFi Direct
- Permission:
ACCESS_WIFI_STATE,CHANGE_WIFI_STATE,ACCESS_FINE_LOCATION(API 23+) - อุปกรณ์ 2 เครื่องขึ้นไป ที่รองรับ WiFi Direct
ขั้นตอนที่ 1: สร้างโปรเจกต์
Android Studio → New Project → Empty Activity
ขั้นตอนที่ 2: Layout (res/layout/activity_main.xml)
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
android:gravity="center">
<TextView
android:id="@+id/tvStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="WiFi Direct: OFF"
android:textSize="18sp"
android:layout_marginBottom="24dp"/>
<Button
android:id="@+id/btnToggle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="เปิด WiFi Direct"
android:padding="16dp 32dp"/>
<Button
android:id="@+id/btnDiscover"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ค้นหาอุปกรณ์"
android:padding="16dp 32dp"
android:layout_marginTop="16dp"
android:enabled="false"/>
<ListView
android:id="@+id/lvPeers"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginTop="16dp"/>
</LinearLayout>
ขั้นตอนที่ 3: WifiDirectBroadcastReceiver.java
package com.example.wifidirect;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.p2p.WifiP2pManager;
import android.widget.Toast;
public class WifiDirectBroadcastReceiver extends BroadcastReceiver {
private final WifiP2pManager manager;
private final WifiP2pManager.Channel channel;
private final MainActivity activity;
public WifiDirectBroadcastReceiver(WifiP2pManager manager, WifiP2pManager.Channel channel, MainActivity activity) {
this.manager = manager;
this.channel = channel;
this.activity = activity;
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
// สถานะ WiFi Direct เปลี่ยน (เปิด/ปิด)
int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
activity.updateWifiDirectState(state == WifiP2pManager.WIFI_P2P_STATE_ENABLED);
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
// รายการอุปกรณ์เพื่อน (Peers) เปลี่ยนแปลง
if (manager != null && channel != null) {
manager.requestPeers(channel, activity.peerListListener);
}
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
// สถานะการเชื่อมต่อเปลี่ยน
// TODO: ดึง NetworkInfo และจัดการเชื่อมต่อ
} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
// ข้อมูลอุปกรณ์ตัวเองเปลี่ยน
}
}
}
ขั้นตอนที่ 4: MainActivity.java (Logic หลัก)
package com.example.wifidirect;
import android.content.BroadcastReceiver;
import android.content.IntentFilter;
import android.net.wifi.p2p.WifiP2pManager;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.ArrayAdapter;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pDeviceList;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private WifiP2pManager manager;
private WifiP2pManager.Channel channel;
private BroadcastReceiver receiver;
private IntentFilter intentFilter;
private TextView tvStatus;
private Button btnToggle, btnDiscover;
private ListView lvPeers;
private ArrayAdapter peersAdapter;
private List peerList = new ArrayList<>();
// Listener สำหรับรับรายการ Peers
public final WifiP2pManager.PeerListListener peerListListener = new WifiP2pManager.PeerListListener() {
@Override
public void onPeersAvailable(WifiP2pDeviceList peers) {
peerList.clear();
peerList.addAll(peers.getDeviceList());
updatePeersList();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvStatus = findViewById(R.id.tvStatus);
btnToggle = findViewById(R.id.btnToggle);
btnDiscover = findViewById(R.id.btnDiscover);
lvPeers = findViewById(R.id.lvPeers);
peersAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1);
lvPeers.setAdapter(peersAdapter);
// เริ่มต้น WifiP2pManager
manager = (WifiP2pManager) getSystemService(WIFI_P2P_SERVICE);
channel = manager.initialize(this, getMainLooper(), null);
// สร้าง Receiver
receiver = new WifiDirectBroadcastReceiver(manager, channel, this);
// กำหนด Action ที่จะรับ
intentFilter = new IntentFilter();
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
btnToggle.setOnClickListener(v -> toggleWifiDirect());
btnDiscover.setOnClickListener(v -> discoverPeers());
}
private void toggleWifiDirect() {
// WiFi Direct ใช้ WiFi ปกติ ต้องเปิด WiFi ก่อน
// หมายเหตุ: ไม่มี API ตรงๆ สำหรับ toggle P2P only ใช้ WifiManager แทน
// แต่ WifiP2pManager จะทำงานเมื่อ WiFi เปิดอยู่
}
private void discoverPeers() {
if (manager != null && channel != null) {
manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
tvStatus.setText("กำลังค้นหาอุปกรณ์...");
}
@Override
public void onFailure(int reason) {
tvStatus.setText("ค้นหาล้มเหลว: " + reason);
}
});
}
}
public void updateWifiDirectState(boolean enabled) {
runOnUiThread(() -> {
if (enabled) {
tvStatus.setText("WiFi Direct: ON");
btnToggle.setText("ปิด WiFi Direct");
btnDiscover.setEnabled(true);
} else {
tvStatus.setText("WiFi Direct: OFF");
btnToggle.setText("เปิด WiFi Direct");
btnDiscover.setEnabled(false);
peersAdapter.clear();
}
});
}
private void updatePeersList() {
runOnUiThread(() -> {
peersAdapter.clear();
for (WifiP2pDevice device : peerList) {
peersAdapter.add(device.deviceName + "\n" + device.deviceAddress);
}
peersAdapter.notifyDataSetChanged();
});
}
@Override
protected void onResume() {
super.onResume();
registerReceiver(receiver, intentFilter);
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(receiver);
}
}
ขั้นตอนที่ 5: AndroidManifest.xml
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="com.example.wifidirect">
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- Hardware Feature (Optional - สำหรับ Filter บน Play Store) -->
<uses-feature android:name="android.hardware.wifi.direct" android:required="true" />
<application ...>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
🔄 ขั้นตอนการเชื่อมต่อเต็มรูปแบบ (Connection Flow)
- Initialize:
manager.initialize() - Discover Peers:
manager.discoverPeers() - Get Peers:
manager.requestPeers()→PeerListListener - Connect:
manager.connect()ด้วยWifiP2pConfig(ระบุ deviceAddress, wps.setup = PBC) - Connection Info:
manager.requestConnectionInfo()→ConnectionInfoListener(ได้ Group Owner IP) - Transfer Data: ใช้ Socket ต่อที่ Group Owner IP (Port 8888 หรือที่กำหนด)
โค้ดเชื่อมต่อ (Connect)
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = selectedDevice.deviceAddress;
config.wps.setup = WpsInfo.PBC; // Push Button Config
manager.connect(channel, config, new WifiP2pManager.ActionListener() {
@Override public void onSuccess() { /* กำลังเชื่อมต่อ... */ }
@Override public void onFailure(int reason) { /* ล้มเหลว */ }
});
รับข้อมูลการเชื่อมต่อ
manager.requestConnectionInfo(channel, new WifiP2pManager.ConnectionInfoListener() {
@Override
public void onConnectionInfoAvailable(WifiP2pInfo info) {
if (info.groupFormed) {
String hostAddress = info.groupOwnerAddress.getHostAddress();
if (info.isGroupOwner) {
// ตัวเองเป็น Server (Group Owner) - เปิด ServerSocket
startServer(hostAddress);
} else {
// ตัวเองเป็น Client - ต่อ Socket ไปที่ hostAddress
connectToServer(hostAddress);
}
}
}
});
⚠️ ข้อควรระวังและข้อจำกัด
- ต้องเปิด WiFi ก่อน - WiFi Direct ทำงานบน WiFi Radio เดียวกัน
- Android 10+ (API 29): ต้องมี
ACCESS_FINE_LOCATIONและ Location Services เปิดอยู่ - ไม่ทำงานบน Emulator - ต้องทดสอบบนอุปกรณ์จริง 2 เครื่อง
- Battery Drain: การ Discover ต่อเนื่องใช้แบตเตอรี่สูง
- Channel Conflict: อาจขัดแย้งกับ WiFi Infrastructure Mode
📱 การทดสอบ
- ติดตั้งแอปบนอุปกรณ์ 2 เครื่อง
- เปิด WiFi ทั้งคู่
- กด "เปิด WiFi Direct" → ควรเห็นสถานะ ON
- กด "ค้นหาอุปกรณ์" ทั้งคู่
- จะเห็นรายชื่ออุปกรณ์อีกเครื่องใน ListView
- คลิกเลือกอุปกรณ์ → เรียก
connect()เพื่อจับคู่