목차

반응형

1. 개요

2. 사용하는 라이브러리, 개념 설명

3. 코드

4. 그 외

 

 

 

1. 개요

노드 서버 백엔드상에서 파일을 주고 받는 경우가 있다.

그런 경우 axios나 request를 통해 주고받는데 생각보다 예제 코드가 많지 않아서 지금 사용중인 코드를 올리도록 하겠다.

reqeust로도 가능하지만 요청 실패시 catch 부분에 대한 설정을 못하는 것 같아서(찾아봐도 안나오더라) axios로 갈아탔다.

 

2. 사용하는 라이브러리, 개념 설명

사용하는 라이브러리

axios 네트워크 통신

form-data axios의 네트워크 요청 시 파일 업로드같이 특수한 형태의 요청을 설정하기 위해서 필요하다.

filesystem 파일에 대하여 관리할 수 있도록 도와주는 라이브러리 이미 fs로 쓰고 있을 가능성이 높음.

 

3가지 라이브러리를 설치하고 나면 파일 업로드에 대한 개발이 가능하다.

코드로 넘어가기 전에 간단히 어떤 플로우를 통하여 업로드 하는지 알아보자

 

1. formdata 변수 생성

2. formdata에 파일 stream 데이터 주입

3. axios에 생성해둔 formdata로 요청

 

3. 코드

//1. formdata 변수 생성
const formData = new FormData();

//2. formdata에 파일 stream 데이터 주입
formData.append("promisedParamName", fileSystem.createReadStream(`target.jpg`));

const requestConfig = {
    url: "https://mytargetsite.com/api/file/photoinfra/uploads",
    headers: {
        'Content-Type':'multipart/form-data; boundary=' + formData.getBoundary()
    },
    data: formData
}

//3. axios에 생성해둔 formdata로 요청
AxiosNetworkHelper.PostRequest(requestConfig).then(res =>{
    if(res.status === 200) console.log("성공")
    else console.log(`요청 실패 ${res.status}`)
}).catch(error => {console.log(`전송 실패 ${error}`)})

 

자세한 설명은 하지않겠다.

다만 저기서 formData.getBoundary()가 어떤 역할을 하는지 알려주겠다.

웹 request가 날아갈때 multipart의 경우 boundary라고 해서 데이터간의 구획을 나누는 역할을 해주는 표지판 역학을 하는 코드가 필요한데 그 정보를 axios의 요청에 넣어주는 것 이다.(이해 안가면 아래 웹 리퀘스트 참고)

Accept: application/json, text/plain, */*
Content-Type: application/x-www-form-urlencoded
User-Agent: axios/0.21.1
Transfer-Encoding: chunked


Content-Type: multipart/form-data; boundary=--------------------------637277032015795830863476
content-length: 67576

 

4. 그 외

현재 게시물의 예제는 단일 이미지 업로드에 대한 예제다.

근데 살다보면 단일 이미지 업로드가 아닌 2개 이상의 이미지 업로드를 해야 할 필요가 있다.

다음은 그런 경우에 대한 예제 코드를 올리도록 하겠다.

 

nodejs axios readstream 파일 업로드

nodejs axios writestream 파일 다운로드

반응형
반응형

오류

Vue에서 Swiper를 사용할 경우 인터넷 익스플로러에서 작동 안하며 콘솔에서 아래와 같이 에러 메시지를 볼 수있다.

"개체가 'isNaN' 속성이나 메서드를 지원하지 않습니다."

 

원인

IE에서는 ES6 문법에 속하는 isNan이나 entries를 사용할 수 없다.

 

 

해결

vue.config.js 파일의 transpileDependencies에 dom7, swiper를 추가해준다.

 

아래 2개 링크는 참고한 사이트다.

github.com/surmon-china/vue-awesome-swiper/issues/665

sjquant.tistory.com/38

 

반응형
반응형

증상

유니티 버전을 2019대에서 2020대로 올리고 안드로이드 빌드를 하면 

mainTemplate.gradle file is using the old aaptOptions noCompress property definition which does not include types defined by unityStreamingAssets constant.

에러와 함께 빌드 실패한다.

 

해결방법

Project Settings > Player > Publishing Settings > Build > Custom Main Gradle Template 체크

 

생성된 mainTemplate.gradle파일에 아래에 aaptOptions 부분에 noCompress = ['.ress', '.resource', '.obb'] + unityStreamingAssets.tokenize(', ') 추가

 

참고

answers.unity.com/questions/1802208/build-error-27.html

반응형
반응형

증상

유니티에서 안드로이드 빌드 시작하자마자

CommandInvokationFailure: Failed to update Android SDK package list.

stderr[
Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema
at com.android.repository.api.SchemaModule$SchemaModuleVersion.<init>(SchemaModule.java:156)
at com.android.repository.api.SchemaModule.<init>(SchemaModule.java:75)
at com.android.sdklib.repository.AndroidSdkHandler.<clinit>(AndroidSdkHandler.java:81)
at com.android.sdklib.tool.sdkmanager.SdkManagerCli.main(SdkManagerCli.java:73)
at com.android.sdklib.tool.sdkmanager.SdkManagerCli.main(SdkManagerCli.java:48)
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.annotation.XmlSchema
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(Unknown Source)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(Unknown Source)
at java.base/java.lang.ClassLoader.loadClass(Unknown Source)
... 5 more

라는 에러와 함께 빌드 실패처리

 

해결방법

뭐 jdk를 재설치하고 external tools에서 JDK 경로 재설정하고 이것저것 하라고 나와있는데 나의 경우 해결방법은 이것이었다.

 

Edit > Preferences > External Tools > JDK Installed with Unity의 경로의 자동 설정을 체크해제 > 맨마지막에 슬래시 추가

 

이해가 안가지만 이렇게 하니까 잘된다.

 

참고

forum.unity.com/threads/failed-to-update-android-sdk-package-list-error-when-using-sdk-installed-with-unity.722777/

반응형
반응형

증상

유니티 안드로이드 빌드 시 아래와 같은 에러

/Users/jim/Desktop/workspace/project/project/Temp/gradleOut/launcher/build/intermediates/merged_manifests/release/AndroidManifest.xml:52: AAPT: error: unexpected element found in

 

해당 파일의 52번째 줄에는 <quries>라는 신택스가 있는데 인식을 못하는 것 같다.

 

원인

stackoverflow.com/questions/62969917/how-do-i-fix-unexpected-element-queries-found-in-manifest

 

How Do I Fix "unexpected element found in "?

All of a sudden, I am getting this build error in my Android project: unexpected element found in How do I fix it?

stackoverflow.com

 

유니티의 gradle 버전이 3.4.0 인데 버전이 낮아서 그렇다고 한다.

 

해결

Gradle 버전 3.4.0 -> 3.4.3으로 변경한다.

위의 Grade의 com.android.tools.build:gradle:3.4.0'라고 적혀있는 부분을 com.android.tools.build:gradle:3.4.3'으로 바꿔주고 유니티 빌드를 다시 해보자.

 

위 파일의 경로는 아래와 같다.

/Applications/Unity/Hub/Editor/2019.4.15f1/PlaybackEngines/AndroidPlayer/Tools/GradleTemplates/baseProjectTemplate.gradle

반응형
반응형

증상

xcode로 프로젝트를 아이폰에 빌드, 실행도 잘되고 아카이브, 업로드도 잘되는데 출시하려고 좀 기다리면 "잘못된 바이너리로 상태가 변경되었습니다."라고 메시지가 날아오면서 해당 바이너리가 사라져 버린다.

아무런 설명 없이 날아가버리는데 뭐가 문제일까?

 

원인

알고 보니 회사 공식 메일(앱스토어가 연결되어 있는 공식 계정)에 바이너리가 거절된 이유를 상세하게 설명한 메일이 와 있었다.

내가 해당 메일 접근 권한이 없어서 메일이 온지도 전혀 몰랐던 것이다.

당신도 앱스토어 공식 계정으로 메일이 왔는지 확인해보라

 

메일에는 아래와 같은 내용이 와 있었다.

Dear Developer,
We identified one or more issues with a recent delivery for your app, “Mecha head League” 1.0.11 (115). Please correct the following issues, then upload again.
ITMS-90683: Missing Purpose String in Info.plist - Your app’s code references one or more APIs that access sensitive user data. The app’s Info.plist file should contain a NSPhotoLibraryUsageDescription key with a user-facing purpose string explaining clearly and completely why your app needs the data. Starting Spring 2019, all apps submitted to the App Store that access user data are required to include a purpose string. If you’re using external libraries or SDKs, they may reference APIs that require a purpose string. While your app might not use these APIs, a purpose string is still required. You can contact the developer of the library or SDK and request they release a version of their code that doesn’t contain the APIs. Learn more (https://developer.apple.com/documentation/uikit/core_app/protecting_the_user_s_privacy).
Though you are not required to fix the following issues, we wanted to make you aware of them:
ITMS-90078: Missing Push Notification Entitlement - Your app appears to register with the Apple Push Notification service, but the app signature’s entitlements do not include the ‘aps-environment’ entitlement. If your app uses the Apple Push Notification service, make sure your App ID is enabled for Push Notification in the Provisioning Portal, and resubmit after signing your app with a Distribution provisioning profile that includes the ‘aps-environment’ entitlement. Xcode does not automatically copy the aps-environment entitlement from provisioning profiles at build time. This behavior is intentional. To use this entitlement, either enable Push Notifications in the project editor’s Capabilities pane, or manually add the entitlement to your entitlements file. For more information, see https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/HandlingRemoteNotifications.html#//apple_ref/doc/uid/TP40008194-CH6-SW1.
Best regards,
The App Store Team

developer.apple.com

Local and Remote Notification Programming Guide: Configuring Remote Notification Support

Describes how apps can send and receive user notifications locally and remotely.

 

사람마다 증상은 다를 것이고 그에 따라 메일 내용도 다를 것이다. 메일의 내용을 대략 해석하자면

  1. 프로젝트가 photolibrary를 사용하기 때문에 photolibrary 사용에 관한 안내 문구를 제시해야 한다.
  2. Push Notification을 사용하는데 설정이 제대로 안되어있다.

 

해결

1. 프로젝트가 photolibrary를 사용하기 때문에 photolibrary 사용에 관한 안내 문구를 제시해야 한다.

info.plist에 설정 추가

<key>NSPhotoLibraryUsageDescription</key>
<string>Photo Library Access Warning</string>

 

2. Push Notification을 사용하는데 설정이 제대로 안되어있다.

Signing & Capabilities > +Capabilties > Push Notification 추가를 해준다.

 

위의 설정대로만 해주면 정상적으로 업로드 및 출시가 가능하다.

반응형
반응형

1. 개요

2. 중복 로그인 막는 원리

3. 코드

4. 유의사항

 

 

 

 

 

 

 

 

1. 개요

어느 정도 사이즈가 있어서 파이어베이스 로그인을 필요로 하는 게임을 만드는데 2개의 디바이스에서 동일한 소셜 정보로 순차대로 로그인하면 별도의 처리가 없으면 로그인이 잘만 된다.

악용하는 유저도 있고 수많은 버그를 불러일으키는 행위이기 때문에 예방을 필요로 한다.

골치가 아프다. 어떻게 해야지 중복 로그인을 막을 수 있을까?

파이어베이스 실시간 DB의 onvaluechanged 기능을 사옹하면 쉽게 처리 가능하다.

 

 

 

2. 중복 로그인 막는 원리

중복처리를 막기 위한 플로우는 다음과 같다.

 

1. 유저의 소셜 로그인(구글, 애플)

2. 유저 개인 정보를 보관하는 곳에 유저의 device id를 업데이트

3. 유저의 device id에 onvaluechange 트리거를 연결

4. 트리거 작동시 바뀐 값과 현재 유저의 device id가 같은지 확인, 다르면 중복 로그인 팝업과 함께 게임 종료 처리

 

 

3. 코드

1,2 단계는 생략하고 3,4번 코드만 올리도록 하겠다.

 

3. 유저의 device id에 onvaluechange 트리거를 연결하는 코드

DatabaseReference DBRef;

 

//DBRef는 본인 상황에 맞게 적절한 위치를 가져와야 한다.

DBRef = FirebaseDatabase.GetInstance("DB 이름").RootReference;

 

DBRef.Child("Device ID의 위치").ValueChanged += LogoutFunction;

 

4. 트리거 작동 시 바뀐 값과 현재 유저의 device id가 같은지 확인, 다르면 중복 로그인 팝업과 함께 게임 종료 처리

private void LogoutFunction(object sender, ValueChangedEventArgs args)
{
  if (args.DatabaseError != null) 
  {
      Debug.LogError(args.DatabaseError.Message);
      return;
  }

  //device id와 받은 값이 다른 경우
  if (SystemInfo.deviceUniqueIdentifier != (string) args.Snapshot.Value) 
  {
  	//로그아웃 처리
  }
}

 

 

4. 유의사항

당연하지만 유저가 device id 값을 바꾸기 전에 이벤트를 미리 걸어버리면 안 된다.

반응형
반응형

열심히 일을 하다보면 aab 파일에 문제가 없는지 궁금할때가 있다.

유니티 build and run을 사용하지 않고 aab 파일을 핸드폰에 설치하는 방법에 대해서 알아보자

 

쉬운 방법은 없다 그냥 아래 써있는대로 따라하자

 

본인의 OS에 맞춰 bundletool을 설치하자

github.com/google/bundletool/releases

 

cmd 기준 bundletool을 사용하여 aab파일로부터 apk를 뽑아내는 명령어는 아래와 같다.

 

java -jar /Users/jim/Desktop/workspace/project/bundletool-all-1.3.0.jar  build-apks --bundle=/Users/jim/Desktop/workspace/project/Test/app.aab  --output=/Users/jim/Desktop/workspace/project/Test/result.apks --ks=/Users/jim/Desktop/document/keystore/key.keystore --ks-pass=qlalfqjsgh --ks-key-alias=mycompany --key-pass=qlalfqjsgh --mode=universal

 

빨간색에 해당하는 부분은 본인의 환경에 맞춰서 바꿔넣어야한다.

 

뽑아낸 apks 파일의 확장자를 zip으로 변경하자

 

확장자를 바꾼 파일의 압축을 풀면 한개의 apk가 나올것이다.

해당 파일을 설치하면 된다.

 

adb 설치 명령어까지 친절하게

./adb install /Users/jim/Downloads/reuslt.apk 

반응형
반응형

새로 바뀐 플레이스토어에서 apk 또는 aab를 업로드하면 위와 같이 원인은 안알려주고 에러메시지만 틱 뱉는다.

계속 시도해봐도 안되는데 이런 경우 현재 로그인된 계정 명의가 정확하지 않아서라고 한다.

크롬 시크릿 모드로 다시 로그인해서 업로드 하거나 모든 계정을 로그아웃하고 다시 하나의 계정만 로그인하고 업로드하면 잘된다.

 

반응형
반응형

1. 개요

몰랐는데 사실 유니티 IAP(in app purchase) 상품에 대한 국가별 화폐 단위 및 가격을 하드코딩 없이 손쉽게 불러오고 표출하는 방법이 있었다.

따라서 유니티 클라이언트에 상품별 결제 가격에 대한 정보를 전혀 기입할 필요가 없다!

나도 이 기능은 나중에야 알았다. 이런...!

 

2. 원리

1. IAP 상품 정보 등록 및 Initialize

2. product id로 상품 정보 단일 조회

3. 상품 정보에 내재되어있는 로컬 가격과 로컬 화폐단위 획득 및 표출

 

 

3. 코드

1번은 너무 흔하디 흔하니까 스킵하도록 한다. IAP에 대한 코드가 전혀 없다면 아래 페이지를 참고하자

learn.unity.com/tutorial/unity-iap#5c7f8528edbc2a002053b46e

 

Unity IAP - Unity Learn

Unity IAP (In App Purchases) lets you sell a variety of items directly within your free or paid game including premium content, virtual goods and subscriptions. In this tutorial, we are going to look at how to add IAP to an existing game project. This tuto

learn.unity.com

 

 

2. product id로 상품 정보 단일 조회

일반적인 IAP 스크립트라면 라면 IStoreController 타입의 변수 m_StoreController를 가지고 있을 것이다.

해당 변수로부터 product id를 통하여 원하는 product를 리턴해주는 함수를 하나 만들자

public Product GetProduct(string _productId)
{
	return m_StoreController.products.WithID(_productId);
}

 

 

3. 상품 정보에 내재되어있는 로컬 가격과 로컬 화폐단위 획득 및 표출

if (shopItem.ItemType == ItemType.Package)
{
	textPPrice.text = string.Format("{0} {1}", IAP.instance.GetProduct(shopItem.ProductId).metadata.localizedPrice, IAP.instance.GetProduct(shopItem.ProductId).metadata.isoCurrencyCode);
}

위의 코드에 대한 부가설명을 하겠다.

위의 코드는 상품 UI에 부착되어서 textPPrice라는 text 컴포넌트의 텍스트를 지정해주는 부분이다.

상품 UI는 최초에 초기화 단계에서 표출해주는 상품에 대한 product id를 가지고 있어서 위에서 IAP에 만들어뒀던 product 조회 함수를 통해 플레이스토어 및 앱스토어에 등록된 상품에 대한 정보를 가져올 수 있다.

shopItem.ProductId로 조회한 product의 metadata.localizedPrice는 현지 화폐 단위의 가격을 의미하고 metadata.isoCurrencyCode는 화폐 단위를 의미한다.

예를 들어 10000원짜리 상품을 한국 유저의 경우 text에는 10000 KRW라고 표기된다.

 

4. 특이사항

해당 강좌의 전제 조건은 이미 플레이스토어 및 앱스토어에 상품 정보가 등록되어있다고 가정하에 진행했다. 상품 정보를 등록 안 하면 데이터가 안 나오는 게 당연하다.

에디터에서는 전부다 0.01 USD라고 표기된다. 에디터에서만 그렇게 표기되니까 당황하지말고 디바이스에서 테스트해보자

반응형