2026/04/29

오늘의 이야기

 




🔗 Google Nearby Connections API 완전 정복 가이드


오늘날 모바일 애플리케이션에서 기기 간 통신은 점점 중요해지고 있습니다. Google의 Nearby Connections API는 인터넷 연결 없이도 가까운 거리의 기기들 간에 안전하고 빠른 데이터 통신을 가능하게 하는 강력한 도구입니다.


 


앱 적용 예시


 


📱 Nearby Connections API란?


Nearby Connections API는 Google이 제공하는 크로스 플랫폼 API로, 다음과 같은 특징을 가집니다:



  • 오프라인 통신: 인터넷 연결 없이 기기 간 직접 통신

  • 다중 프로토콜 지원: Bluetooth, WiFi Direct, WiFi LAN 자동 선택

  • 높은 보안성: 모든 통신은 암호화되어 전송

  • 크로스 플랫폼: Android와 iOS 모두 지원

  • 쉬운 구현: 복잡한 네트워크 설정 없이 간단한 API 호출로 구현


💡 실생활 활용 사례
- 멀티플레이어 게임 (오프라인 대전)
- 파일 공유 앱
- 협업 도구 (화이트보드, 프레젠테이션)
- IoT 기기 제어
- 비상 상황 통신 시스템

🏗️ 기본 구조 및 개념


1. 주요 역할



  • Advertiser (광고자): 다른 기기가 발견할 수 있도록 자신을 광고하는 기기

  • Discoverer (발견자): 근처의 광고 중인 기기를 찾는 기기


🔄 동작 과정
1. Advertiser가 서비스를 광고 시작
2. Discoverer가 근처 기기를 탐색
3. 기기 발견 및 연결 요청
4. 연결 승인 후 데이터 송수신
5. 연결 종료

⚙️ 프로젝트 설정


build.gradle (Module: app) 설정


// Nearby Connections API 의존성 추가
implementation 'com.google.android.gms:play-services-nearby:19.0.0'

android {
compileSdk 34

defaultConfig {
minSdk 21 // Nearby API 최소 요구사항
targetSdk 34
}
}

AndroidManifest.xml 권한 설정


<!-- 필수 권한들 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<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_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<!-- Android 12 이상을 위한 새로운 권한 -->
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" />

⚠️ 중요한 주의사항
Android 6.0 (API 23) 이상에서는 런타임 권한 요청이 필수입니다. 특히 위치 권한은 Bluetooth와 WiFi 스캔에 필요합니다.

🚀 기본 구현 예제


1. MainActivity - 기본 설정 및 권한 처리


public class MainActivity extends AppCompatActivity {
private static final String TAG = "NearbyConnections";

// 서비스 ID - 같은 앱끼리 통신하기 위한 고유 식별자
private static final String SERVICE_ID = "com.yourapp.nearbyconnections";

// 연결 상태를 추적하기 위한 변수들
private String connectedEndpointId = "";
private boolean isAdvertising = false;
private boolean isDiscovering = false;

// UI 컴포넌트들
private Button btnStartAdvertising, btnStartDiscovery, btnSendMessage;
private TextView tvStatus, tvMessages;
private EditText etMessage;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// UI 컴포넌트 초기화
initializeViews();

// 권한 요청
requestNecessaryPermissions();

// 버튼 클릭 리스너 설정
setupClickListeners();
}

/**
* UI 컴포넌트들을 초기화하는 메소드
*/
private void initializeViews() {
btnStartAdvertising = findViewById(R.id.btnStartAdvertising);
btnStartDiscovery = findViewById(R.id.btnStartDiscovery);
btnSendMessage = findViewById(R.id.btnSendMessage);
tvStatus = findViewById(R.id.tvStatus);
tvMessages = findViewById(R.id.tvMessages);
etMessage = findViewById(R.id.etMessage);

// 초기 상태 설정
updateUI();
}

/**
* 필요한 권한들을 요청하는 메소드
*/
private void requestNecessaryPermissions() {
String[] permissions = {
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
};

// Android 12 이상에서 추가 권한 확인
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
permissions = new String[] {
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.BLUETOOTH_ADVERTISE,
Manifest.permission.BLUETOOTH_CONNECT,
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.NEARBY_WIFI_DEVICES
};
}

// 권한이 없는 경우 요청
ActivityCompat.requestPermissions(this, permissions, 1001);
}

2. 광고 시작 (Advertiser 역할)


/**
* 다른 기기들이 이 기기를 발견할 수 있도록 광고를 시작하는 메소드
*/
private void startAdvertising() {
// 광고 옵션 설정
AdvertisingOptions advertisingOptions = new AdvertisingOptions.Builder()
.setStrategy(Strategy.P2P_CLUSTER) // 1:N 연결 전략
.build();

// 연결된 기기의 이름 (다른 기기에서 보여질 이름)
String localEndpointName = Build.MODEL; // 기기 모델명 사용

Nearby.getConnectionsClient(this)
.startAdvertising(
localEndpointName, // 광고할 기기 이름
SERVICE_ID, // 서비스 ID
connectionLifecycleCallback, // 연결 생명주기 콜백
advertisingOptions // 광고 옵션
)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void unused) {
// 광고 시작 성공
isAdvertising = true;
updateStatus("광고 시작됨 - 다른 기기에서 발견 가능");
updateUI();
Log.d(TAG, "광고 시작 성공");
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
// 광고 시작 실패
updateStatus("광고 시작 실패: " + e.getMessage());
Log.e(TAG, "광고 시작 실패", e);
}
});
}

3. 기기 탐색 시작 (Discoverer 역할)


/**
* 근처의 광고 중인 기기들을 탐색하는 메소드
*/
private void startDiscovery() {
// 탐색 옵션 설정
DiscoveryOptions discoveryOptions = new DiscoveryOptions.Builder()
.setStrategy(Strategy.P2P_CLUSTER) // 광고와 동일한 전략 사용
.build();

Nearby.getConnectionsClient(this)
.startDiscovery(
SERVICE_ID, // 찾을 서비스 ID
endpointDiscoveryCallback, // 기기 발견 콜백
discoveryOptions // 탐색 옵션
)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void unused) {
// 탐색 시작 성공
isDiscovering = true;
updateStatus("탐색 시작됨 - 근처 기기 검색 중...");
updateUI();
Log.d(TAG, "탐색 시작 성공");
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
// 탐색 시작 실패
updateStatus("탐색 시작 실패: " + e.getMessage());
Log.e(TAG, "탐색 시작 실패", e);
}
});
}

4. 기기 발견 콜백


/**
* 기기 발견 시 호출되는 콜백
*/
private final EndpointDiscoveryCallback endpointDiscoveryCallback =
new EndpointDiscoveryCallback() {
@Override
public void onEndpointFound(@NonNull String endpointId,
@NonNull DiscoveredEndpointInfo info) {
// 새로운 기기 발견!
Log.d(TAG, "기기 발견: " + info.getEndpointName());
updateStatus("기기 발견: " + info.getEndpointName() + " - 연결 시도 중...");

// 자동으로 연결 요청 보내기
requestConnection(endpointId, info.getEndpointName());
}

@Override
public void onEndpointLost(@NonNull String endpointId) {
// 기기 연결 끊어짐
Log.d(TAG, "기기 연결 끊어짐: " + endpointId);
updateStatus("기기 연결이 끊어졌습니다.");
}
};

/**
* 발견된 기기에 연결을 요청하는 메소드
*/
private void requestConnection(String endpointId, String endpointName) {
Nearby.getConnectionsClient(this)
.requestConnection(
Build.MODEL, // 내 기기 이름
endpointId, // 연결할 기기 ID
connectionLifecycleCallback // 연결 생명주기 콜백
)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void unused) {
// 연결 요청 전송 성공
Log.d(TAG, "연결 요청 전송됨: " + endpointName);
updateStatus("연결 요청 전송됨: " + endpointName);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
// 연결 요청 실패
Log.e(TAG, "연결 요청 실패", e);
updateStatus("연결 요청 실패: " + e.getMessage());
}
});
}

5. 연결 생명주기 관리


/**
* 연결의 생명주기를 관리하는 콜백
*/
private final ConnectionLifecycleCallback connectionLifecycleCallback =
new ConnectionLifecycleCallback() {
@Override
public void onConnectionInitiated(@NonNull String endpointId,
@NonNull ConnectionInfo connectionInfo) {
// 연결이 시작됨 - 사용자에게 승인/거절 선택권 제공
Log.d(TAG, "연결 요청 받음: " + connectionInfo.getEndpointName());

// 자동으로 연결 승인 (실제 앱에서는 사용자 확인 받는 것이 좋음)
Nearby.getConnectionsClient(MainActivity.this)
.acceptConnection(endpointId, payloadCallback);

updateStatus("연결 승인됨: " + connectionInfo.getEndpointName());
}

@Override
public void onConnectionResult(@NonNull String endpointId,
@NonNull ConnectionResolution result) {
switch (result.getStatus().getStatusCode()) {
case ConnectionsStatusCodes.STATUS_OK:
// 연결 성공!
Log.d(TAG, "연결 성공: " + endpointId);
connectedEndpointId = endpointId;
updateStatus("연결 완료! 메시지를 보낼 수 있습니다.");

// 탐색과 광고 중지 (1:1 연결이므로)
stopDiscovery();
stopAdvertising();

updateUI();
break;

case ConnectionsStatusCodes.STATUS_CONNECTION_REJECTED:
// 연결 거절됨
Log.d(TAG, "연결 거절됨: " + endpointId);
updateStatus("연결이 거절되었습니다.");
break;

default:
// 기타 연결 실패
Log.d(TAG, "연결 실패: " + endpointId);
updateStatus("연결에 실패했습니다.");
break;
}
}

@Override
public void onDisconnected(@NonNull String endpointId) {
// 연결 끊어짐
Log.d(TAG, "연결 끊어짐: " + endpointId);
connectedEndpointId = "";
updateStatus("연결이 끊어졌습니다.");
updateUI();
}
};

6. 데이터 송수신


/**
* 메시지를 전송하는 메소드
*/
private void sendMessage(String message) {
if (connectedEndpointId.isEmpty()) {
updateStatus("연결된 기기가 없습니다.");
return;
}

// 텍스트 메시지를 바이트 배열로 변환
Payload bytesPayload = Payload.fromBytes(message.getBytes());

// 메시지 전송
Nearby.getConnectionsClient(this)
.sendPayload(connectedEndpointId, bytesPayload)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void unused) {
// 전송 성공
Log.d(TAG, "메시지 전송 성공: " + message);
appendMessage("나: " + message);
etMessage.setText(""); // 입력 필드 초기화
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
// 전송 실패
Log.e(TAG, "메시지 전송 실패", e);
updateStatus("메시지 전송 실패: " + e.getMessage());
}
});
}

/**
* 데이터 수신을 처리하는 콜백
*/
private final PayloadCallback payloadCallback = new PayloadCallback() {
@Override
public void onPayloadReceived(@NonNull String endpointId, @NonNull Payload payload) {
// 데이터 수신됨
if (payload.getType() == Payload.Type.BYTES) {
// 바이트 데이터인 경우 (텍스트 메시지)
String receivedMessage = new String(payload.asBytes());
Log.d(TAG, "메시지 수신: " + receivedMessage);

// UI 업데이트는 메인 스레드에서 실행
runOnUiThread(() -> {
appendMessage("상대방: " + receivedMessage);
});
}
}

@Override
public void onPayloadTransferUpdate(@NonNull String endpointId,
@NonNull PayloadTransferUpdate update) {
// 전송 상태 업데이트 (파일 전송 시 진행률 표시 등에 사용)
if (update.getStatus() == PayloadTransferUpdate.Status.SUCCESS) {
Log.d(TAG, "페이로드 전송 완료");
} else if (update.getStatus() == PayloadTransferUpdate.Status.FAILURE) {
Log.e(TAG, "페이로드 전송 실패");
}
}
};

7. UI 업데이트 및 정리 메소드


/**
* UI 상태를 업데이트하는 메소드
*/
private void updateUI() {
runOnUiThread(() -> {
// 연결 상태에 따라 버튼 활성화/비활성화
btnSendMessage.setEnabled(!connectedEndpointId.isEmpty());
btnStartAdvertising.setEnabled(!isAdvertising);
btnStartDiscovery.setEnabled(!isDiscovering);
});
}

/**
* 상태 메시지를 업데이트하는 메소드
*/
private void updateStatus(String message) {
runOnUiThread(() -> {
tvStatus.setText(message);
});
}

/**
* 메시지를 채팅창에 추가하는 메소드
*/
private void appendMessage(String message) {
runOnUiThread(() -> {
tvMessages.append(message + "\n");
});
}

/**
* 탐색을 중지하는 메소드
*/
private void stopDiscovery() {
if (isDiscovering) {
Nearby.getConnectionsClient(this).stopDiscovery();
isDiscovering = false;
Log.d(TAG, "탐색 중지됨");
}
}

/**
* 광고를 중지하는 메소드
*/
private void stopAdvertising() {
if (isAdvertising) {
Nearby.getConnectionsClient(this).stopAdvertising();
isAdvertising = false;
Log.d(TAG, "광고 중지됨");
}
}

@Override
protected void onDestroy() {
super.onDestroy();

// 앱 종료 시 모든 연결 해제 및 서비스 중지
Nearby.getConnectionsClient(this).disconnectFromAllEndpoints();
stopDiscovery();
stopAdvertising();
}

📋 레이아웃 파일 (activity_main.xml)


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">

<!-- 상태 표시 -->
<TextView
android:id="@+id/tvStatus"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="준비됨"
android:textSize="16sp"
android:padding="8dp"
android:background="#E3F2FD"
android:textColor="#1976D2" />

<!-- 제어 버튼들 -->
<Button
android:id="@+id/btnStartAdvertising"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="광고 시작 (다른 기기에서 발견 가능)"
android:layout_marginTop="16dp" />

<Button
android:id="@+id/btnStartDiscovery"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="기기 탐색 시작"
android:layout_marginTop="8dp" />

<!-- 메시지 입력 -->
<EditText
android:id="@+id/etMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="보낼 메시지를 입력하세요"
android:layout_marginTop="16dp" />

<Button
android:id="@+id/btnSendMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="메시지 전송"
android:enabled="false"
android:layout_marginTop="8dp" />

<!-- 메시지 표시 -->
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginTop="16dp">

<TextView
android:id="@+id/tvMessages"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="메시지가 여기에 표시됩니다.\n"
android:textSize="14sp"
android:padding="8dp"
android:background="#F5F5F5" />
</ScrollView>

</LinearLayout>

🎯 고급 기능 및 팁


1. 파일 전송


/**
* 파일을 전송하는 메소드
*/
private void sendFile(Uri fileUri) {
try {
// 파일에서 Payload 생성
Payload filePayload = Payload.fromFile(fileUri);

// 파일 정보를 먼저 전송 (파일명, 크기 등)
String fileInfo = "FILE:" + getFileName(fileUri) + ":" + getFileSize(fileUri);
Payload infoPayload = Payload.fromBytes(fileInfo.getBytes());

// 정보 먼저 전송
Nearby.getConnectionsClient(this)
.sendPayload(connectedEndpointId, infoPayload);

// 그 다음 파일 전송
Nearby.getConnectionsClient(this)
.sendPayload(connectedEndpointId, filePayload);

} catch (Exception e) {
Log.e(TAG, "파일 전송 실패", e);
}
}

2. 연결 전략 선택


📊 연결 전략 비교
P2P_CLUSTER: 1:N 연결, 많은 기기와 동시 연결
P2P_STAR: 1:1 연결, 안정적이고 빠른 속도
P2P_POINT_TO_POINT: 1:1 전용, 최고 성능

3. 에러 처리 및 디버깅


/**
* 상세한 에러 처리를 포함한 연결 메소드
*/
private void connectWithErrorHandling(String endpointId) {
Nearby.getConnectionsClient(this)
.requestConnection(Build.MODEL, endpointId, connectionLifecycleCallback)
.addOnFailureListener(exception -> {
// 구체적인 에러 타입별 처리
if (exception instanceof ApiException) {
ApiException apiException = (ApiException) exception;
switch (apiException.getStatusCode()) {
case ConnectionsStatusCodes.STATUS_ENDPOINT_UNKNOWN:
updateStatus("기기를 찾을 수 없습니다.");
break;
case ConnectionsStatusCodes.STATUS_NETWORK_NOT_CONNECTED:
updateStatus("네트워크에 연결되지 않았습니다.");
break;
case ConnectionsStatusCodes.STATUS_BLUETOOTH_ERROR:
updateStatus("블루투스 오류가 발생했습니다.");
break;
default:
updateStatus("연결 오류: " + apiException.getStatusCode());
break;
}
}
});
}

4. 보안 강화


/**
* 연결 시 보안 인증을 추가하는 예제
*/
private void secureConnectionHandling(String endpointId, ConnectionInfo info) {
// 연결 토큰 검증 (실제 앱에서는 더 복잡한 인증 로직 구현)
String authToken = info.getAuthenticationDigits();

// 사용자에게 인증 토큰 확인 요청
new AlertDialog.Builder(this)
.setTitle("연결 확인")
.setMessage("다음 기기와 연결하시겠습니까?\n" +
"기기명: " + info.getEndpointName() + "\n" +
"인증 코드: " + authToken)
.setPositiveButton("승인", (dialog, which) -> {
// 연결 승인
Nearby.getConnectionsClient(this)
.acceptConnection(endpointId, payloadCallback);
})
.setNegativeButton("거절", (dialog, which) -> {
// 연결 거절
Nearby.getConnectionsClient(this)
.rejectConnection(endpointId);
})
.show();
}

🚀 성능 최적화 팁


1. 배터리 최적화


/**
* 배터리 효율적인 설정
*/
private void optimizedAdvertising() {
AdvertisingOptions options = new AdvertisingOptions.Builder()
.setStrategy(Strategy.P2P_CLUSTER)
// 저전력 모드 사용
.setLowPower(true)
.build();

// 일정 시간 후 자동으로 광고 중지
Handler handler = new Handler();
handler.postDelayed(() -> {
stopAdvertising();
updateStatus("배터리 절약을 위해 광고가 중지되었습니다.");
}, 60000); // 1분 후 중지
}

2. 연결 품질 모니터링


/**
* 연결 품질을 모니터링하는 클래스
*/
public class ConnectionQualityMonitor {
private long lastMessageTime = 0;
private int failedMessages = 0;
private static final long TIMEOUT_MS = 5000; // 5초 타임아웃

public void onMessageSent() {
lastMessageTime = System.currentTimeMillis();
}

public void onMessageFailed() {
failedMessages++;
if (failedMessages > 3) {
// 연결 품질이 나쁘다고 판단, 재연결 시도
reconnectWithBetterStrategy();
}
}

private void reconnectWithBetterStrategy() {
// 더 안정적인 전략으로 재연결
// 예: P2P_STAR 전략 사용
}
}

🔧 문제해결 가이드


⚠️ 자주 발생하는 문제들

1. 기기를 발견하지 못하는 경우:
- 위치 권한이 허용되었는지 확인
- 블루투스와 WiFi가 켜져있는지 확인
- 같은 SERVICE_ID를 사용하는지 확인

2. 연결이 자주 끊어지는 경우:
- 기기 간 거리가 너무 멀지 않은지 확인
- 다른 무선 신호 간섭이 없는지 확인
- 적절한 연결 전략을 선택했는지 확인

3. 메시지가 전송되지 않는 경우:
- 연결 상태를 확인
- 페이로드 크기 제한 확인 (최대 32KB)
- 네트워크 상태 확인

디버깅을 위한 로그 설정


/**
* 상세한 로깅을 위한 헬퍼 클래스
*/
public class NearbyLogger {
private static final String TAG = "NearbyConnections";

public static void logConnectionState(String endpointId, String state) {
Log.d(TAG, String.format("연결 상태 변경 - ID: %s, 상태: %s, 시간: %s",
endpointId, state, new Date()));
}

public static void logPayloadInfo(Payload payload) {
Log.d(TAG, String.format("페이로드 정보 - ID: %d, 타입: %s, 크기: %d",
payload.getId(),
payload.getType().name(),
payload.asBytes() != null ? payload.asBytes().length : 0));
}
}

🎨 UI/UX 개선 아이디어


연결 상태 시각화


/**
* 연결 상태를 시각적으로 표시하는 메소드
*/
private void updateConnectionStatus(boolean isConnected) {
runOnUiThread(() -> {
if (isConnected) {
// 연결됨 - 녹색 표시
tvStatus.setBackgroundColor(ContextCompat.getColor(this, R.color.green_light));
tvStatus.setTextColor(ContextCompat.getColor(this, R.color.green_dark));
tvStatus.setText("🟢 연결됨 - 메시지 전송 가능");
} else {
// 연결 안됨 - 회색 표시
tvStatus.setBackgroundColor(ContextCompat.getColor(this, R.color.grey_light));
tvStatus.setTextColor(ContextCompat.getColor(this, R.color.grey_dark));
tvStatus.setText("⚪ 연결 대기중");
}
});
}

/**
* 메시지에 타임스탬프 추가
*/
private void appendMessageWithTimestamp(String message) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
String timestamp = sdf.format(new Date());
String formattedMessage = String.format("[%s] %s", timestamp, message);

runOnUiThread(() -> {
tvMessages.append(formattedMessage + "\n");
// 스크롤을 맨 아래로 이동
scrollView.post(() -> scrollView.fullScroll(View.FOCUS_DOWN));
});
}

📱 실제 앱 적용 사례


멀티플레이어 게임 구현


/**
* 간단한 멀티플레이어 게임을 위한 데이터 구조
*/
public class GameData {
private String playerName;
private int playerScore;
private String gameAction;

// JSON으로 직렬화하여 전송
public String toJson() {
return new Gson().toJson(this);
}

public static GameData fromJson(String json) {
return new Gson().fromJson(json, GameData.class);
}
}

/**
* 게임 데이터 전송
*/
private void sendGameAction(String action, int score) {
GameData gameData = new GameData();
gameData.playerName = Build.MODEL;
gameData.playerScore = score;
gameData.gameAction = action;

sendMessage(gameData.toJson());
}

🎯 마무리 및 다음 단계


Nearby Connections API는 오프라인 환경에서도 강력한 기기 간 통신을 제공하는 훌륭한 도구입니다. 이 가이드를 통해 기본적인 구현부터 고급 기능까지 다뤄보았습니다.


핵심 포인트 요약:



  • ✅ 적절한 권한 설정이 성공의 열쇠

  • ✅ 연결 전략을 용도에 맞게 선택

  • ✅ 에러 처리를 통한 안정성 확보

  • ✅ 사용자 경험을 고려한 UI 설계

  • ✅ 배터리 최적화로 실용성 향상


추천 학습 경로:



  1. 기본 예제로 동작 원리 이해

  2. 파일 전송 기능 추가

  3. 보안 강화 및 인증 구현

  4. 실제 앱에 통합 및 최적화

  5. iOS와의 크로스 플랫폼 통신 구현


🚀 다음 프로젝트 아이디어
- 오프라인 채팅 앱
- 파일 공유 도구
- 멀티플레이어 보드게임
- 협업 화이트보드
- IoT 기기 제어 앱

Nearby Connections API의 무한한 가능성을 탐험하며 혁신적인 앱을 만들어보세요! 궁금한 점이나 더 자세한 구현 방법이 필요하다면 공식 문서를 참고하시기 바랍니다.




이 가이드가 도움이 되셨다면 ⭐를 눌러주세요!
더 많은 안드로이드 개발 팁은 블로그에서 만나보실 수 있습니다.






댓글 없음:

댓글 쓰기

오늘의 이야기

이글 대표 이미지 💡 Eclipse에서 PyDev 오프라인 설치하는 방법 오늘은 PyDev 를 Eclipse에 오프라인으로 설치 하는 방법에 대해 정리해보았습니다. 인터넷 연결이 어려운 환경에서도 Pytho...