728x90
text-decoration: underline solid #8e8e93;
728x90
반응형
728x90

1. 설치

// android sdk version > 30
yarn add @react-native-admob/admob

// android sdk version > 30
yarn add @react-native-admob/admob@1.5.1

cd ios && pod install && cd ..

 

 

2. App ad id 설정

// info.plist
<key>GADApplicationIdentifier</key>
<string>ca-app-pub-YYYYYYY~YYYYYYY</string>
<key>SKAdNetworkItems</key>
<array>
  <dict>
    <key>SKAdNetworkIdentifier</key>
    <string>cstr6suwn9.skadnetwork</string>
  </dict>
</array>


// android/app/src/main/Anroidmeniest.xml
<application>
<meta-data android:name="com.google.android.gms.ads.APPLICATION_ID" android:value="ca-app-pub-YYYYYYY~YYYYYY"/>
</application>

 

 

3. app-ads.txt

구글 애드몹 사이트에 로그인해서 앱을 등록을 먼저 해야한다.

앱이 이미 출시되어있다면 정말 쉽게 등록 가능하다.

(출시 안되어있을떄는 어떤지는 모르겠다.)

 

앱을 모두 등록한뒤

좌측 메뉴 목록 중에서 "앱 > 모든 앱 보기" 를 선택한다.

 

그러면 app-ads.txt 탭을 볼 수 있다.

일단 2번 항목을 복사하고 닫자.

 

구글 공식 크롤링 가이드에 따르면

도메인 단위로 app-ads.txt를 수집한다고 한다.

 

예를들어,

앱 스토어/플레이 스토어에 지원 페이지 링크가

www.help.com/service  라면

www.help.com/app-ads.txt  을 크롤링 하여

등록 여부를 체크하는것이다.

 

따라서, 우리는 해당 링크에 접근했을 때

app-ads.txt가 보여지게 설정해줘야 한다.

(각자 환경에 맞게)

 

app-ads.txt의 내용은

위에 2번 항목을 복사한 내용이면 충분하다.

 

 

4. 앱 정상 실행 확인하기

라이브러리를 설치하고나면

앱이 정상적으로 잘 실행되는지

확인 할 필요가 있습니다.

 

각 os에서 앱을 실행해보고

에러가 난다면

npm start --reset-cache

를 통해 캐시를 한번

정리해주는것을 추천드립니다.

 

 

5. 테스트 코드로 광고 띄워보기

function AdTest() {
  const TEST_FULLPAGE_VIDEO_AD = 'ca_~~~';
  const { adLoaded, adDismissed, show, load } = useInterstitialAd(TEST_FULLPAGE_VIDEO_AD)
  
  const showAd = () => {
    const isNotShownAd = adLoaded && !adDismissed;
    if (isNotShownAd) {
      show();
    }
  }
  
  return {
    <>
      <TouchalbeOpacity onPress={showAd}>
        <Text>광고 짠</Text>
      </TouchableOpacity>
    </>
  }
}

광고를 보여주고나면

adDisimissed가 true 상태로 전환되는데

load 메소드를 통해

광고를 리필(?)해 줄 수 있습니다.

리필 후에는 adDismissed가 다시 false로 전환되며

필요에따라 다시 광고를 띄워줄 수 있습니다

728x90
반응형
728x90

옵션에 vertical을 부여했을때

위와 같은 에러가 발생함을 발견했다.

 

크기 지정에 있어 에러가 발생하는듯 했고

Carousel의 Props을 확인해보니

Vertical 속성이 부여됐을때

sliderHeight와 itemHeight가 필수 옵션임을 확인할 수 있었다.

 

두 옵션을 임의로 지정해준 결과

에러가 해결됐음을 확인할 수 있었다.

 

에러가 발생했을때는 마땅한 이유가 있다.

특히, 라이브러리 사용에 있어 에러가 발생한 경우에는

제작자의 의도대로 사용하지 않았을 확률이 제법 있다.

 

에러 로그를 정확히 확인하고

분석하는 노력을 해보자.

728x90
반응형
728x90

글로벌 서비스를 개발할때

기본 언어를 해당 사용자에 맞게

설정해주는 것은

사용자를 위한 최소한의 배려이다

 

간단하게

react-native 앱의 기본언어

설정 방법에 대해 알아본다.

 

[ 목차 ]

1. 디바이스 OS별 언어 설정 불러오기

2. 기본 언어 설정해주기

3. 전체 상태 변경

 

import {NativeModules, Platform} from 'react-native';

const useLanguageState = () => {
  useLayoutEffect(() => {
    const language = getSystemLanguage();
    console.log(language);
  }, []);
  
  const getSystemOriginLanguage = () => {
    let systemLanguage = '';
    if (Platform.OS === 'ios') {
      systemLanguage = NativeModules.SettingsManager.settings.AppleLocale
      || NativeModules.SettingsManager.settings.AppleLanguages[0];
    } else {
      NativeModules.I18nManager.localeIdentifier;
    }
    
    const language = systemLanguage.toLowerCase().indexOf('ko') >= 0 ? 'KR' : 'EN';
    return language;
  }
}

OS별로 시스템 랭귀지리를 불러와

콘솔에 찍어 확인해보았다.

 

기본 언어를 설정해주어야 하는데

앱이 재실행 됐을때도 해당 언어로

상태를 유지해주기위해

스토리지에 저장해 주도록 한다.

 

import {NativeModules, Platform} from 'react-native';
import storage from '@react-native-async-storage/async-storage';

type LanguageTypes = 'KR' | 'EN';

const useLanguageState = () => {
  useLayoutEffect(() => {
    const language = getSystemLanguage();
    setupUserLanguage(language);
  }, []);
  
  const getSystemOriginLanguage = () => {
    let systemLanguage = '';
    if (Platform.OS === 'ios') {
      systemLanguage = NativeModules.SettingsManager.settings.AppleLocale
      || NativeModules.SettingsManager.settings.AppleLanguages[0];
    } else {
      NativeModules.I18nManager.localeIdentifier;
    }
    
    const language = systemLanguage.toLowerCase().indexOf('ko') >= 0 ? 'KR' : 'EN';
    return language;
  }
  
  const setupUserLanguage = async (systemLanguage: LanguageTypes) => {
    const savedLanguage = await storage.getItem('language');
    if (!savedLanguage) {
      await updateUserDefaultLanguage(systemLanguage);
    }
  }
  
  const updateUserDefaultLanguage = async (lang: LanguageTypes) => {
    await storage.setItem('language', lang);
  } 
}

storage에 이전에 저장된 값이 있으면

갱신을 생략하고 없으면 갱신하는 구조이다.

 

이제 변경된 상태를

global state관리 도구로

서비스 전체에 적용해주면 되는데

여기서는 react-redux를 사용한다.

 

 

import {NativeModules, Platform} from 'react-native';
import {useDispatch, useSelector} from 'react-redux';
import storage from '@react-native-async-storage/async-storage';

import {RootState} from '@redux/store';
import {changeGlobalLanguage} from '@redux/setup/actions';

type LanguageTypes = 'KR' | 'EN';

const useLanguageState = () => {
  const dispatch = useDispatch();
  const { globalLanguage } = useSelector((state: RootState) => state.setup);

  useLayoutEffect(() => {
    const language = getSystemLanguage();
    setupUserLanguage(language);
  }, []);
  
  const getSystemOriginLanguage = () => {
    let systemLanguage = '';
    if (Platform.OS === 'ios') {
      systemLanguage = NativeModules.SettingsManager.settings.AppleLocale
      || NativeModules.SettingsManager.settings.AppleLanguages[0];
    } else {
      NativeModules.I18nManager.localeIdentifier;
    }
    
    const language = systemLanguage.toLowerCase().indexOf('ko') >= 0 ? 'KR' : 'EN';
    return language;
  }
  
  const setupUserLanguage = async (systemLanguage: LanguageTypes) => {
    const savedLanguage = await storage.getItem('language');
    await updateUserDefaultLanguage(systemLanguage);
  }
  
  const updateUserDefaultLanguage = async (lang: LanguageTypes) => {
    dispatch(changeGlobalLanguage(lang));
    await storage.setItem('language', lang);
  }
  
  return { language: globalLanguage };
}

 

store는 각자 구성해보도록 하자.

단순히 KR -> EN -> ... 등으로 string 변경만 해주는 수준이니

어렵지 않게 설정 가능할것이다.

728x90
반응형
728x90

[solved path issue when app is updated!!]

 

react-native-sound의

issue를 아무리 뒤져봐도 찾을수가 없지만

내게 이슈로 다가왔던

 

업데이트 후 이전 버전에서 다루던

로컬 음원파일이 재생이 안되는 이슈를 해결했다.

 

[이전 방식]

1. 음원 생성

react-native-audio로

로컬에 녹음된 음원을 저장하고

해당 경로를 저장한다.

 

2. 음원 재생

저장된 경로로 부터

음원 파일을 불러와 재생한다.

 

3. 결과

일반적인 경우 문제없으나

앱 업데이트 후 재생이 안되는 이슈 발생

 

 

[문제 해결한 방식]

1. 음원 생성

react-native-audio로

로컬에 녹음된 음원을 저장하고

해당 파일명만 저장한다.

 

2. 음원 재생

저장된 파일명과 AudioUtils.LibraryDirectoryPath를 이용해

음원 파일을 불러와 재생한다.

 

3. 결과

일반적인 경우에도

앱 업데이트 후에도 재생이 잘 된다.

728x90
반응형
728x90

background processing 설정 후

빌드를 진행하는 도중

info.plist 설정 관련 에러가 발생했다.

 

 

 위 기능을 사용하기 위해서는

이 설정을 추가적으로 해주어야 한다.

728x90
반응형
728x90

(ios에서) 앱을 껐다 다시 켜면

react-native-sound의 실행이

정상적으로 이뤄지지 않는 경우가 발생했다.

 

나의 경우에는

react-native-audio와 sound 두개를 모두 사용하는데

두개를 함께 쓰는 환경에서는

playback 셋팅을 해주지 않으면 안된다고한다.

 

https://github.com/zmxv/react-native-sound/issues/42

 

Sound playing via Receiver instead of phone speaker in IOS · Issue #42 · zmxv/react-native-sound

I have no problems with playing/manipulating the sound file in IOS, but the sound is coming from the receiver so it's not practical. I am using the latest version of this module, testing on Iph...

github.com


정말 어렵게 위의 이슈를 발견했다.

 

Sound.setCategory('Playback')

 

요것 한줄이면 이슈 해결된다.

 

playback 기능을 정상적으로 사용하기 위해서는

이렇게 xcode -> signing & capabilities에서

audio background mode를 활성화 시켜주어야한다.

 

728x90
반응형
728x90

https://mingule.tistory.com/65

 

React에서 setInterval 현명하게 사용하기(feat. useInterval)

들어가기 Babble의 방 목록 페이지에 들어가면 유저가 생성한 방들이 쭉 나열되어 있는 것을 볼 수 있다. (안타깝게도 유저가 없으면 방도 없다ㅜㅜ) 그리고 이 방들은 5초마다 서버에 요청을 보

mingule.tistory.com

위 블로그에서 언급한 원인으로

불완전한 함수인 setInterval로 인해

버그를 맞이할수있다.

 

간략히 말하자면

setInterval이 지연 시간을 보장해주지 않기 때문

 

따라서 ,

나는 빠른 주기로

state를 업데이트 하는

stopWatch 훅스를 만들때

아래와 같이 처리해서 목적을

달성하였따.

export function useStopWatch(start: boolean) {
  const [time, setTime] = useState(0);

  useEffect(() => {
    let interval: any = null;
        
    if (start) {
      const startedTime = Date.now();
      interval = setInterval(() => {
        setTime(Date.now() - startedTime);
      }, 50);
    } else {
      if (interval) clearInterval(interval);
    }

    return () => {
      if (interval) clearInterval(interval);
    }
  }, [start]);

  return { time, setTime };
}
728x90
반응형
728x90

어리석게도

Map을 써야하는 때에도 계속해서 

객체를 써온것 같다.

 

기초를 다시 다지기위해

오래전 봤던 책을 다시 보는 과정에서

깨달은 바를 기록한다.

 

Map은 객체와 유사하고

Set은 배열과 유사하다.

 

Map

객체는 활용도가 높고 상당히 자유도가 부여되지만

그에따라 아래와 같은 문제가 있다.

1. 프로토타입 체인 때문에 의도치 않은 연결이 발생할 수 있다.

2. 객체 안에 연결된 키와 값이 몇개나 되는지 쉽게 알아낼 수 없다.

// 객체 예제
const object1 = {
  "height": 100,
  "width": 200
};

// 객체 크기
Object.keys(object1).length;

// Map 예제
const map1 = new Map();
map1
  .set("height", 100)
  .set("width", 200);
  
// Map 크기
map1.size;

3. 키는 반드시 문자열이나 심볼이어야 하므로 객체를 키로 써서 값과 연결할 수 없다.

// 객체
const object2 = {
  "user": "USER",
  "admin": "ADMIN"
};

// Map
const map2 = new Map();
map2
  .set("user", "USER")
  .set("admin", "ADMIN");
  
const guest = "unknown_001";
map2.set(guest, "GUEST");

4. 객체는 프로퍼티 순서를 전혀 보장하지 않습니다.

 

 

Set

Set은 배열과 유사하지만

중복을 허용하지 않는 데이터의 집합이라는

큰 장점이 있다.

 

다르게 말하면 Set에서는

중복 검사 자체가 필요없다는 뜻이다.

Set에서 중복 데이터를 add하면

해당 액션은 무시된다. (아무일도 일어나지 않음)

 

const users = new Set();
users
  .add("jaeky")
  .add("julia");

users.delete("jaeky");
users.size;
728x90
반응형
728x90

1. 변수, 함수명을 보다 구체적이고 직관적으로 작성하라

> 변수, 함수명을 짓는데 시간을 들여 곰곰히 생각해보라.

내가 지금 무엇을 만들려고 하는건지

정확히 인지하고 설계한뒤 이름을 지어야 

내일의 내가, 혹은 동료가 두번 고생 안한다.

 

2. 추상화를 통해 응집도를 높여라

> 먼저, 순수한 함수(pure function)를 작성하도록 항상 노력하자.

순수한 함수는 입력이 같으면 결과도 반드시 같다는 특성과

부수 효과 (side effect)가 발생하지 않아,

함수를 호출한다고 해서 프로그램의 상태가 바뀌는 일이 없다는

특성을 가지고있다.

순수함수를 쓰면 코드 테스트도 쉽고, 함수를 이해하기도 쉽고,

재사용하기도 훨씬 용이해진다.

 

3. 테스트 코드를 작성하도록 노력하라.

> 그러면 자연스럽게 추상화를 하는 습관을 갖게 될 것이다.

테스트 코드를 짜기위해 기능 단위로

나눠서 함수를 작성하게 될것이고,

명확한 함수의 기능에 맞게 함수명을

지을수 있게 된다.

 

4. 초보/주니어 개발자에서 벗어나려면 자료구조, 디자인 패턴을 공부하라

 

5. Frontend 개발자가 중급개발자로 인정받기 위해서는 시간복잡도 향상에 힘을써라

> Backend 개발자와 달리 Frontend 개발자는 초기에

빠르게 실력이 느는것처럼 보이고

3년차와 5년차 7년차가 구현하는 코드에는

큰 차이가 나지않을수 있다.

화면을 그리는데 들어가는 코드는

필연적으로 길게 늘어지고 보기 안좋아보이기 떄문.

다만, 얼마나 효율적으로 동작하는

모델과 컨트롤러를 작성하는지,

상태 관리를 얼마나 효율적으로 하는지에서

Frontend 개발자의 실력이 들어난다.

 

6. 숏코딩에 힘쓰지말자.

> 예를 들어, 메서드 체이닝을 통한 숏코딩은 직관적이라 괜찮지만 삼항연산자를 통해 길게늘어지는 숏코딩보단 if문으로 직관적으로 작성하자.

728x90
반응형