[React-Native] react <-> react-native Webview 위치 통신

앱 심사 거절

 

expo 프로젝트 빌드 후 앱심사를 받는데 가이드 라인 위반으로 앱 승인이 거절되었다고 했다. 원래 react에서 geolocation을 이용하여 위치를 받은 후 거리순으로 목록들을 나열해주는 기능이 있는데 가이드에 의하면 위치 목적 문자열을 업데이트하여 앱이 요청한 정보를 어떻게 사용하는지 설명하고 데이터가 어떻게 사용되는지 있어야 한다고 한다.

 

expo 프로젝트 빌드 후 앱심사를 받는데 가이드 라인 위반으로 앱 승인이 거절되었다고 했다. 원래 react에서 geolocation을 이용하여 위치를 받은 후 거리순으로 목록들을 나열해주는 기능이 있는데 가이드에 의하면 위치 목적 문자열을 업데이트하여 앱이 요청한 정보를 어떻게 사용하는지 설명하고 데이터가 어떻게 사용되는지 있어야 한다고 한다.

 

위의 이유로 웹뷰 통신을 통하여 웹뷰가 로딩되면 react-native에서 위치 정보를 요청한 후 react로 데이터를 전달하는 코드를 작성하였다. react에서 웹뷰의 메세지를 받는 코드를 작성한 후 메세지를 받으면 콜백함수 onMessageEvent를 작성했다.

 

코드

useEffect(() => {
    if (isMobile() === 'mobile') {
      window.addEventListener('message', onMessageEvent, { capture: true });
      return () => window.removeEventListener('message', onMessageEvent);
    }
  }, []);

이제 native에서 데이터를 보내주기만 하면 되는데.. native는 배포 시 승인을 받기 위해 위치 권한을 요청할 때 ios, android별 설정을 해줘야 한다. 위치권한은 expo를 참고하여 기능에 따라 정확하게 요청하여야 한다.

 

위치 권한 요청 permission 목록 [expo 참조]

locationAlwaysAndWhenInUsePermission: 앱이 항상 위치 정보를 수집해야 하는 경우에 사용

locationAlwaysPermission: 앱이 백그라운드에서도 위치 정보를 계속 수집해야 하는 경우에 사용

locationWhenInUsePermission: 앱이 사용 중일 때만 위치 정보가 필요할 때 사용

 

ios

// app.json

...
"ios": {
      "supportsTablet": true,
      "infoPlist": {
        "NSLocationWhenInUseUsageDescription": "주변의 지점을 추천해 드리기 위해 위치 서비스를 허용하는 것을 권장합니다.(선택사항)",}
...
      [
        "expo-location",
        {
          "locationAlwaysAndWhenInUsePermission": "주변의 지점을 추천해 드리기 위해 위치 서비스를 허용하는 것을 권장합니다.(선택사항)",
          "isIosBackgroundLocationEnabled": false,
          "isAndroidBackgroundLocationEnabled": false
        }
      ]

 

anroid

app.json
"android": {
      ...
      "permissions": [
        "ACCESS_FINE_LOCATION",
        "ACCESS_COARSE_LOCATION",
        ]

 

정리

1. Location.requestForegroundPermissionsAsync()를 사용하여 위치 접근 권한을 요청 후 (granted) 또는 거부되었는지(denied) 확인

let { status } = await Location.requestForegroundPermissionsAsync();

 

2. "denied"인 경우 AsyncStorage를 사용해 hasShownLocationAlert 키에 저장된 값을 확인하여, 이미 알림을 표시한 적이 있는지를 확인. 만약 표시된 적이 없다면, Alert를 통해 사용자에게 위치 권한이 필요하다는 메시지를 보여주고, '설정으로 이동' 버튼을 통해 사용자가 직접 설정에서 권한을 변경할 수 있게 유도

if (status !== "granted") {
  // 알림이 이미 표시된 적이 있는지 확인
  const hasShownAlert = await AsyncStorage.getItem(
    "hasShownLocationAlert"
  );

  if (!hasShownAlert) {
    // 권한 거부 시 처리
    Alert.alert(
      "위치 권한 필요",
      "위치 권한이 거부되었습니다. 추후 주변 공간을 찾으시려면 설정에서 변경해주세요.",
      [
        { text: "취소", style: "cancel" },
        {
          text: "설정으로 이동",
          onPress: () => Linking.openSettings(),
        },
      ]
    );

    // 알림이 표시된 것으로 설정
    await AsyncStorage.setItem("hasShownLocationAlert", "true");
  }

 

3. "granted"인 경우 위치정보 가져오기

const locationResult = await Location.getCurrentPositionAsync({
  accuracy: Location.Accuracy.Balanced,
});

 

4. 웹뷰가 있다면 위치 정보 메세지 전달

 useEffect(() => {
    // 처음 컴포넌트가 마운트될 때만 호출
    if (
      webviewRef.current &&
      (location.longitude !== null || location.latitude !== null)
    ) {
      webviewRef.current.postMessage(JSON.stringify(location));
    }
  }, [location]);

결과 화면