728x90
반응형

현재 앱에 fastlane 을 적용하여

 

명령어만 치면 테스트플라이트로 자동 업로드되도록 구축해놓았다.

 

이틀전에 테스트로 한번 배포 하고 오늘 다시 배포하는데

 

No signing certificate "iOS Distribution" found

 

라는 에러가떴다.

 

앱을 혼자개발하기때문에, p12 certification 파일을 절대로 한번세팅하고 변경하지 않는 내입장에서는

 

무슨일인지 궁금했다.

 

일단 로글를 읽어보니 아카이브는 잘되고,

 

testflight로 업로드 하는 과정에서 문제가 발생한것으로 보아

 

xcode 로 oraginzer에서 업로드를 해보았다.

 

xcode 에서는

 

unable to process request - pla update available

 

해당 에러가 보였는데,

 

이는 ios 정책이 업데이트 되고나서

 

새로운 정책을 확인하지않아서 나는 에러였다.

 

해당페이지에서 계약을 읽고 확인을 누르면

 

다시 업로드가 잘된다.

728x90
반응형
728x90
반응형

react-native-webview 를 사용하다보면 

안드로이드에선 가끔 앱 크래시가 난다

 

해결법은 여러가지가 있는데, 

android:hardwareAccelerated="true"

 

해당 값을 false로 바꿔주거나

 

(false 로 바꿔주면 해결은 되지만, 다른 화면에서 화면이 안나올수있다. video 등..)

 

webview style 에 opacity : 0.99, minHeight : 1

 

을 추가해주는 방법들이다.

 

상품 소개 페이지에서 html 을 

 

react-native-autoheight-webview

 

해당 라이브러리로 뿌려주는데

 

안드로이드에서 그냥 앱이꺼져버리는 에러가 나왔다.

 

로그캣으로 보니

 

fatal signal 11 (sigsegv), code 1 (segv_maperr)

 

해당 에러문구가 보였다. 아마 webview 를 사용한 react-native-autoheight-webivew 에서 흔히 나는 크래시 에러라고 생각하고

 

const androidLayerType =
Platform.OS === 'android'
? Platform.Version >= 31
? 'hardware'
: 'software'
: undefined;
androidLayerType={androidLayerType}

 

로 해결하였다.

 

최종코드는

 

으로

 

androidLayerType 속성을 주면 react-native-webview 에서도 크래시가 나지 않는다.

728x90
반응형
728x90
반응형

<TextInput
placeholderTextColor={'black'}
onSubmitEditing={() => props.getData(props.search)}
returnKeyType="search"
/>

 

이런식으로 onSubmitEditing props 를 통해, onPress 이벤트를 넣을 수 있고, 

해당 키보드의 기본인 '완료' 버튼도 변경할 수 있다.

 

ios같은 경우 search 로 세팅하면 '검색'으로 나오고, 안드로이드는 돋보기 모양으로 나온다.

728x90
반응형
728x90
반응형

많은 RN 개발자들이 화면에 웹뷰를 띄울때, react-native-webview 해당 라이브러리를 사용하는 것으로 알고있다.

 

하지만 해당 라이브러리는 치명적인 약점이 있다.

 

종종 안드로이드에서, 웹뷰사용시 app crush 가 나는 경우가있는데, 해당 에러를 찾아보면

 

의 android:hardwareAccelerated를 false 값으로 바꾸라는 해결방법이 많다.

 

하지만, 해당 방법으로 문제해결을 하면, 웹뷰에서의 crash는 사라지지만, react-native-video에서 동영상이 소리만 들리고 화면이 나오지않은 버그가 새로 생긴다.

 

따라서 옳은 workaround 방법으로

 

android:hardwareAccelerated 는 true 값으로 유지한채,

 

webview 컴포넌트의 props 에 minHeight : 1, opacity : 0.99 를 넣어주는 방법이 있다.

 

정확히 왜 해결되는지는 모르지만, 

 

react-native-webview를 사용시 안드로이드에서 앱꺼짐도 막아주고 비디오도 잘 나오는 해결방법이다.

 

728x90
반응형
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
반응형

+ Recent posts