728x90
반응형

 

고민 끝에 완성된 splash screen

 

스플래시화면부터 강렬한 인상을 주고싶은게 모든 앱 제작자의 마음이다.

지금 하고 있는 프로젝트에서는 주 타겟층이 힙한 20/30대기때문에, 많은 애니메이션 효과를 사용하고있다.

 

앱 로딩시 애니메이션 효과를 위해 내가 고민했던 문제는 총 3가지였다.

 

1.처음 splash screen 자체에 gif 를 넣는 방법

2.react-native-lottie-splash-screen 을 사용하여 lottie 파일로 넣는방법

3.splash screen 별도의 영상을 띄우는 방법

 

현재 앱에 최종적으로 적용된 방법은 3번이다.

 

1.5초 정도가 되는 동영상을 lottie 와 gif 로 변경하여 넣어보니 프레임이 많이 떨어지는 느낌을 받았다.

 

react-native-splash-screen 과 react-native-video 를 통하여

splash 스크린을 띄우고, 그뒤에 react-native-video 컴포넌트를 띄운다.

해당 컴포넌트에서 동영상이 모두 플레이가되면 앱화면이 나오도록 하였다.

 

UX적으로, 컴포넌트를 교체하는 것이아닌, 동영상 재생시 컴포넌트 위에 띄워주고 해당 컴포넌트만 제거하는 것이 안정감이 있어서 해당 방법으로 구현하였다.

 

스플레시 화면에서 동영상으로 넘어가는 부분을 매끄럽게 하기위해서, 동영상 부분의 첫 이미지를 스플래시화면으로 넣어놓는 방법도 있는데

 

자연스럽게 로고다음에 동영상이 플레이되는 것이 디자인팀에서 예쁜것 같다는 피드백이와서 해당 화면으로 최종 결정 하였다.

728x90
반응형
728x90
반응형

 

 

 
 

 

https://developer.android.com/reference/android/Manifest.permission

 

Manifest.permission  |  Android Developers

android.inputmethodservice

developer.android.com

해당 내용에 따르면

 

안드로이드는 sdk버전 33 부터 앨범 퍼미션이

 

READ_EXTERNAL_STORAGE

 

에서

READ_MEDIA_IMAGES
READ_MEDIA_VIDEOS

 

등으로 바뀐다.

 

따라서 react-native-permissions 를 사용할때, Platform 의 구분뿐만아니라, 안드로이드의 버전에 따라서도 체크를 해줘야한다.

 

 

728x90
반응형
728x90
반응형

디버그 모드일때는 자연스럽게 작동하던 kakao / google Oauth 는 release 모드 (내부테스트 / 구글스토어)에서 오류가 나곤한다.

 

그때 카카오톡의 오류 메세지는

이고

 

구글의 오류 메세지는 'DEVELOPER_ERROR'

 

이다.

 

이는 SHA1을 구글 / 카카오 개발센터에 등록하지 않았을때 발생하는데, 

 

firebase 에는

 

./gradlew signingReport 를 통해 얻은

 

release / debug sha1 키를 등록해줘야하고

구글 플레이콘솔을 통해 얻은 sha1 키도 등록해줘야한다.

 

이러면 안드로이드의 구글로그인은 완료가 되며

 

https://developers.kakao.com/docs/latest/ko/android/getting-started

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

 

해당 카카오 개발자센터를 참고하여

 

debug / release / 구글 sha1 를 base64로 인코딩하면된다.

 

개발자 센터에 이렇게 sha256키 1개 / sha1 키 3개씩이 등록되면된다.

 

여기서 구글 sha1키를 인코딩하는 명령어는

 

echo "여기에 sha1키를 따옴표 제거하고 붙여넣기" | xxd -r -p | openssl base64 

 

이러면 구글 / 카카오 로그인이 개발 / 릴리즈 / 구글스토어 에서 모두 정상 작동한다.

728x90
반응형
728x90
반응형

일단 해당 작업을 완료하기위해, 백엔드에서 pg 사와 연동이 되어있는 uri 이 필요하다.

 

안드로이드에서

 

boolean java.lang.boolean.booleanvalue()

 

해당 에러때문에 애를 먹었다.

 

일단

 
import SendIntentAndroid from 'react-native-send-intent';

 

해당 npm 에 들어가서 깔아준다.

 

최근 RN 은

compile 을 쓰지않기에

 

로 수정해주고

 

settings.gradle 도 추가하지않았다.

 

MainApplication.java

 

에서도

 

import com.burnweb.rnsendintent.RNSendIntentPackage;

 

임포트만 해주고

 

 

패키지에 따로 추가해주지않았다.

 

<WebView
style={{ flex: 1, width: deviceWidth, height: deviceHeight }}
javaScriptEnabled
javaScriptCanOpenWindowsAutomatically={true}
onShouldStartLoadWithRequest={(event) => {
return onShouldStartLoadWithRequest(event);
}}
setSupportMultipleWindows={false}
source={{ uri: webUrl }}
onError={(err) => console.log('webview ERROR:::', err)}
onMessage={onComplete}
originWhitelist={['*']}
scalesPageToFit={true}
textZoom={100}
/>

 

해당 webview 의 소스코드이다.

 

const onShouldStartLoadWithRequest = useCallback((event) => {
if (event.url.indexOf('wowcomplete') > -1) {
onComplete();
return false;
}
if (
event.url.startsWith('http://') ||
event.url.startsWith('https://') ||
event.url.startsWith('about:blank')
) {
return true;
}
if (Platform.OS === 'android') {
SendIntentAndroid.openAppWithUri(event.url)
.then((isOpened) => {
console.log('isOpened :::::::', isOpened);
})
.catch((err) => {
console.log('openAppWithUri eror ::::', err);
});
return false;
} else {
Linking.openURL(event.url).catch((err) => {
// Alert.alert(
// '앱 실행에 실패했습니다. 설치가 되어있지 않은 경우 설치하기 버튼을 눌러주세요.',
// );
});
return false;
}
}, []);

 

 

onShouldStartLoadWithRequest

 

함수이다.

 

onShouldStartLoadWithRequest

 

callback은 boolean을 리턴해주고, 

 

해당 boolean으로 로딩전에 콜백을 실행하고 로딩을 더 할지말지를 해주는 함수이다.

 

해당 코드들로 하면 안드로이드에서는 정상작동한다.

 

물론 manifest 에 permission들을 추가해줘야한다.

728x90
반응형
728x90
반응형

 

애니메이션 View들을 어떻게 텀을 두고 플레이할까 고민하다가

animated.View 들의 ref 들을 onLayout 콜백에서 index 값의 텀을 두고 실행하게 했다.

 

해당 컴포넌트 코드

 

import { FlatList, TouchableOpacity, View } from 'react-native';
import { upeIp } from './useIp';
import FastImage from 'react-native-fast-image';
import * as Animatable from 'react-native-animatable';
import { useRef } from 'react';

export const Category = () => {
  const { ip } = upeIp();
  const itemRef = useRef<Animatable.View>({});

  return (
    <View style={{ width: '100%', height: 100 }}>
      <FlatList
        horizontal
        showsHorizontalScrollIndicator={false}
        data={ip}
        keyExtractor={(item) => String(item.ipIdx)}
        renderItem={({ item, index }) => {
          return (
            <TouchableOpacity
              onLayout={() =>
                itemRef.current[index].animate(
                  {
                    0: { scale: 0, rotate: '-90deg' },
                    0.5: { scale: 0.5, rotate: '-60deg' },
                    0.75: { scale: 0.8, rotate: '-45deg' },
                    1: { scale: 1.0, rotate: '0deg' },
                  },
                  index * 1000,
                )
              }
            >
              <Animatable.View
                duration={300}
                ref={(ref) => (itemRef.current[index] = ref)}
                style={{
                  width: 100,
                  height: 100,
                  justifyContent: 'center',
                  alignItems: 'center',
                }}
              >
                <View
                  style={{
                    width: 75,
                    height: 75,
                    borderRadius: 50,
                    justifyContent: 'center',
                    alignItems: 'center',
                    shadowColor: '#000',
                    shadowOffset: { width: 3, height: 3 },
                    shadowOpacity: 0.4,
                    shadowRadius: 5,
                    elevation: 3,
                    backgroundColor: 'white',
                  }}
                >
                  <FastImage
                    source={{ uri: item.iconUrl }}
                    style={{
                      width: 75,
                      height: 75,
                      borderRadius: 50,
                    }}
                  />
                </View>
              </Animatable.View>
            </TouchableOpacity>
          );
        }}
      />
    </View>
  );
};

 

아직 미완성이라 style들을 밖으로 빼지않았다.

728x90
반응형
728x90
반응형
 			<View
              style={{
                width: 100,
                height: 100,
                justifyContent: 'center',
                alignItems: 'center',
              }}
            >
              <View
                style={{
                  width: 75,
                  height: 75,
                  borderRadius: 50,
                  justifyContent: 'center',
                  alignItems: 'center',
                  shadowColor: '#000',
                  shadowOffset: { width: 3, height: 3 },
                  shadowOpacity: 0.4,
                  shadowRadius: 5,
                  elevation: 3,
                }}
              >
                <FastImage
                  source={{ uri: item.iconUrl }}
                  style={{
                    width: 75,
                    height: 75,
                    borderRadius: 50,
                  }}
                />
              </View>
            </View>

 

추후 재사용을 위해 메모

728x90
반응형
728x90
반응형

깃랩에 있는 레퍼지토리를 깃허브로 옮길일이 생겼다.

미러링을 걸어놔서 신경을 안쓰고있었는데,

이틀전부터 미러링이 안되고있었다.

 

원인을 찾아보니, 100mb 이상의 커밋이 발생하여 해당 미러링이 안된것으로 보였다.

 

일단 github 에 새로운 레파지토리를 만들고

 

git clone --mirror [클론할 레포지토리]

 

로 커밋메세지등을 클론했다.

 

그 후에, 

 

https://rtyley.github.io/bfg-repo-cleaner/

 

BFG Repo-Cleaner by rtyley

$ bfg --strip-blobs-bigger-than 100M --replace-text banned.txt repo.git an alternative to git-filter-branch The BFG is a simpler, faster alternative to git-filter-branch for cleansing bad data out of your Git repository history: Removing Crazy Big Files Re

rtyley.github.io

 

링크에서 우측

을 통해 커밋로그를 삭제하는 파일을 받아준다.

 

해당 파일을 클론한 레포지토리의 루트에 위치 시켜주고

 

 

 java -jar bfg-1.14.0.jar --strip-blobs-bigger-than 100M [클론한 레퍼지토리.git]

 

를 통해 100M 이상의 커밋 로그를 삭제해준뒤

 

같은 루트에서 cd [클론한 레퍼지토리.git]

 

을 한후, 

 

git push [옮길 레퍼지토리] -f --mirror

 

를 통해 레퍼지토리로 옮겨줬다.

 

후에 다시 gitlab에서 웹훅을 걸어주었다.

728x90
반응형
728x90
반응형

 

이커머스 앱을 준비하면서 당연히 들어가야할 기능중 하나인 주소지 관리를 개발하면서

 

다음 postcode 를 사용하였다.  rn에서 사용하려면 react-native-webview 라이브러리가 설치되어있어야한다.

 

yarn add @actbase/react-daum-postcode

 

yarn add react-native-webview

 

import Postcode from '@actbase/react-daum-postcode';
<Postcode
style={{
width: '100%',
height: '100%',
}}
onError={(e) => console.log(e)}
jsOptions={{ animation: true }}
onSelected={(data) => {
setPostVisible(false);
setZipcode(String(data?.zonecode));
setAddress(data?.address);
console.log(JSON.stringify(data));
}}
/>

 

이런식으로 사용하면된다.

728x90
반응형
728x90
반응형

프론트에서 직접 스토리지에 접근하는건 별로지만,

 

같이 일하는 서버개발자분이 앱에서 바로 S3에 업로드를 부탁하셨다.

 

워낙 라이브러리가 잘되어있어서 업로드를 하는데

 

error code :AccessControlListNotSupported

error message :The bucket does not allow ACLs

 

이라는 에러가 나왔다.

 

AWS 해당 버킷에 들어가서

 

 

편집을 누른 후

 

활성하하면 해결된다.

728x90
반응형
728x90
반응형

jwt decode 를 할 일이 생겼다.

 

yarn add jwt-decode

 

라이브러리를 사용하거나,

 

const parseJwt = (token) => {
try {
return JSON.parse(atob(token.split('.')[1]));
} catch (e) {
console.log('e :::::', e);
return null;
}
};

 

함수를 사용하면되는데,

 

invalid base64 for part #2 (Property 'atob' doesn't exist)

 

라는 에러가 나왔다.

 

app.tsx에서

 

import { decode, encode } from 'base-64';

if (!global.btoa) {
global.btoa = encode;
}

if (!global.atob) {
global.atob = decode;
}
 

 

로 atob / btoa 를 선언해주면 끝

728x90
반응형

+ Recent posts