블로그 이미지
Every unexpected event is a path to learning for you.

카테고리

분류 전체보기 (2741)
Unity3D (30)
Script (91)
Extensions (14)
Effect (3)
NGUI (77)
UGUI (8)
Physics (2)
Shader (36)
Math (1)
Design Pattern (2)
Xml (1)
Tips (200)
Link (22)
World (1)
AssetBundle (25)
Mecanim (2)
Plugins (70)
Trouble Shooting (68)
Encrypt (7)
LightMap (4)
Shadow (4)
Editor (8)
Crash Report (3)
Utility (9)
UnityVS (2)
Facebook SDK (2)
iTween (3)
Font (11)
Ad (14)
Photon (2)
IAP (1)
Google (8)
Android (46)
iOS (41)
Programming (475)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (228)
협업 (58)
3DS Max (3)
Game (12)
Utility (136)
Etc (96)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (54)
Android (15)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (18)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday
05-17 00:10

iOS 키체인을 활용해 문자열을 앱의 삭제 이후에도 보존하는 방법이다. 스크립트 하나를 아래와 같이 작성.

using UnityEngine;
using System.Runtime.InteropServices;
 
public class KeyChain {
   
  #if UNITY_IPHONE || UNITY_STANDALONE_OSX
   
  [DllImport("__Internal")]
  private static extern string getKeyChainUser();
   
  public static string BindGetKeyChainUser()
  {
    return getKeyChainUser();
  }
   
  [DllImport("__Internal")]
  private static extern void setKeyChainUser(string userId);
   
  public static void BindSetKeyChainUser(string userId)
  {
    setKeyChainUser(userId);
  }
   
  [DllImport("__Internal")]
  private static extern void deleteKeyChainUser();
   
  public static void BindDeleteKeyChainUser()
  {
    deleteKeyChainUser();
  }
 
 
  #endif
 
}
한 스크립트의 함수를 받을 Objective-C 파일을 만들 차례.

당연하게 새롭게 만들거나 다운로드한 파일의 위치는 유니티 프로젝트 Plugins/IOS에 위치. (위에 만든 스크립트 위치는 상관없음)


[링크] <- 링크를 통해 아래의 2개 파일을 다운로드.

- UICKeyChainStore.h

- UICKeyChainStore.m



아래의 2개의 파일을 새롭게 생성.

- KeyChainPlugin.h

- KeyChainPlugin.mm


KeyChainPlugin.h의 내용은 아무것도 구현하지 않고 빈 파일로 둠.


KeyChainPlugin.mm의 내용은 아래와 같이 작성.

#import "KeyChainPlugin.h"
#import "UICKeyChainStore.h"
 
NSString *_keyForID = @"UserID";
 
@implementation KeyChainPlugin
 
extern "C" {
    char* getKeyChainUser();
    void setKeyChainUser(const char* userId);
    void deleteKeyChainUser();	
}


char* getKeyChainUser()
{
    NSString *userId = [UICKeyChainStore stringForKey:_keyForID];
 
    if (userId == nil || [userId isEqualToString:@""]) {
        NSLog(@"No user information");
		userId = @"";
    }
 
	NSString* json = [NSString stringWithFormat:@"{\"userId\":\"%@\"}",userId];
 
    return makeStringCopy([json UTF8String]);
}
 
void setKeyChainUser(const char* userId)
{
    NSString *nsUseId = [NSString stringWithCString: userId encoding:NSUTF8StringEncoding];
 
    [UICKeyChainStore setString:nsUseId forKey:_keyForID];
}
 
void deleteKeyChainUser()
{
    [UICKeyChainStore removeItemForKey:_keyForID];
}
 
char* makeStringCopy(const char* str)
{
    if (str == NULL) {
        return NULL;
    }
 
    char* res = (char*)malloc(strlen(str) + 1);
    strcpy(res, str);
    return res;
}
 
@end

전체적인 흐름은 다음과 같음.


1. Keychain.getKeyChainUser() 호출.

2. KeychainPlugin.getKeyChainUser() 진입후, UICKeyChainStore.stringForKey함수를 사용하여 키체인에 접근, UserID의 키에 해당하는 값을 가져옴.

3. 함수를 보면 알겠지만, 값이 null이거나 빈값일 경우 json으로 리턴할 데이터에 값을 따로 지정하지 않음.

4. {"UserID":"ABC"} 형태로 리턴되므로, 유니티에서 해당 값을 반은 후 JSON 데이터를 파싱해서 사용.


* 유니티 API의 SystemInfo.deviceUniqueIdentifier은 호출시 고유한 값을 리턴하지만,  앱을 삭제하고 다시 설치후 호출할 경우 변경된 값을 리턴하므로, 위와 같은 방법을 통해 영구적인 형태로 사용할 수 있음.



참고링크

- http://bribser.co.jp/blog/pluginkeychain/

- http://docs.unity3d.com/kr/current/Manual/PluginsForIOS.html

- https://github.com/kishikawakatsumi/UICKeyChainStore



출처: http://redccoma.tistory.com/134 [My Data Factory]


반응형
Posted by blueasa
, |


[링크] http://redccoma.tistory.com/129

반응형
Posted by blueasa
, |

프로젝트를 하고 완성이 될 무렵, 게임이 굉장히 괴랄한 프레임을 뿌려대며 제대로 굴러가지 않기 시작했다.

필자의 컴퓨터는 사양이 굉장히 좋다고 자부할 수 있는 컴퓨터였다. 유니티 에디터가 잘못인지 소스코드 상에서 문제가 있는 것인지 보기 위해 탐색을 시작하게 되었고. 프로파일러를 통해 개선할 부분을 다수 개선하였다.


이 밑부터는 내가 경험한 것을 바탕으로 최적화를 한 방법에 대해 서술한다.

 - 프로젝트 진행시 참고했던 박민근 님의 유니티 최적화 테크닉을 참고하였다.

 - http://www.slideshare.net/agebreak/141206-42456391 [링크]

 - 아마 위 파워포인트를 정리한거라고 보면 될 듯 싶다. (그 외에 추가한 것들도 존재한다. 이것들은 오리지날..)


1. 소스코드 병목의 파악.


그 누구나 먼저 볼 곳이 아마도 자신의 소스코드에 대한 문제가 아닐까 싶다.

리소스가 문제라고 해서 리소스를 바꿧는데, 그럼에도 불구하고 문제가 있으면 그 것은 좀 아니다 싶지 않은가?


- DP Call

- 복잡한 연산

- 3D의 수많은 버텍스, 연산

- 픽셀, 오버 드로우

- 셰이더의 많은 연산

- 압축되지 않고 큰 텍스쳐들

- 고 해상도 프레임 버퍼


2. 스크립트 최적화


- 유니티 객체들은 멤버변수에 저장하여, 캐싱을 이용하는게 좋다.

 -> 예를 들자면, Find 라는 검색이 붙은 것들은 왠만하면 지속적으로 사용하지 않는게 좋다. 왜냐하면 Find 들은 프로젝트안의 모든 오브젝트를 순환하며 그 안의 클래스의 스트링을 비교하기 때문이다.


- Instantiate, Destroy 이 두 놈의 프리팹 생성/해제는 비용이 상당히 크다.

 -> 프리펩은 미리 생성해둔후 오브젝트를 풀에서 쓰도록 하자.


- Update 함수 보다는 Coroutine을 사용하는게 좋다.

 -> Update 함수를 쓰지말고, Coroutine을 무한 루틴시켜서 사용하도록 하자. 필자같은 경우에는 게임 관련은 전부 Coroutine에서 사용을 했으며 UI 같은 경우 메인 업데이트에서 돌렸다.


- 나눗셈 말고 곱셈의 사용.

 -> 나눗셈은 곱셈보다 연산속도가 월등히 느리다 100 / 10 이런식으로 사용하지말고 100 * 0.1 을 사용하라는 소리.


- 박싱과 언박싱은 부하가 큰 작업 이므로 많이 사용하지 말자.

 -> 박싱과 언 박싱이란. 

 --> http://vallista.tistory.com/entry/C-%EB%B0%95%EC%8B%B1%EA%B3%BC-%EC%96%B8%EB%B0%95%EC%8B%B1 [링크]


- Magnitude 보다 sqrMagnitude를 사용하여 비교해서 쓴다. (제곱근 계산 X)

 -> Unity 공식 문서에도 써져있다. 

 --> If you only need to compare magnitudes of some vectors, you can compare squared magnitudes of them using sqrMagnitude (computing squared magnitudes is faster).


- 삼각함수의 값은 상수로 저장하고 사용하는게 좋다.


- 문자열은 readonly 혹은 const 키워드를 사용하여, 가비지 컬렉션으로부터 벗어나도록 한다.


3. 가비지 컬렉터


- 우리가 쓰고있는 MonoBehavior는 메모리 관리에 GC가 자동호출되도록 설계되어 있는데, 이 GC가 프로그래머들한테는 좋을 수도 있고, 안좋을 수도 있다. GC가 실행되는 동안 유저들은 게임에서 갑자기 렉이 걸리며, 그렇지 않기위해 우리는 게임을 GC를 피해 만들어야 한다. (필자한테는 상당히 거리낌이 있다.) 이제 이 GC와 친하게 지내기위해 우리도 몇가지 방법을 써서 길들여야하는데, 그 방법에 대해 서술한다. 


- 무엇이든 동적 생성 및 해제는 부하가 굉장히 큰 작업이다. 그래서 위에 언급했다시피 오브젝트 풀 기법을 사용하여 메모리를 관리하도록 하자.


- 오브젝트가 해제되면 다음과정으로는 GC가 동작되서 렉이 걸릴수 밖에 없다. 즉 오브젝트를 만들어 둔 후 활성화 또는 비 활성화를 이용하여 사용하도록 하자.


- 문자열 병합은 StringBuilder의 Append를 사용하면 된다. 왜냐하면 string + string은 임시 문자열을 뱉기 때문에 가비지 컬렉션이 일어나는 환경을 제공한다.


- foreach 대신에 for를 이용하도록 한다. Foreach는 한번 돌리면 24byte의 쓰레기 메모리를 생성시키며 수많이 돌면 더 많은 메모리를 생성시키므로 for을 이용하도록 한다.


- 태그 비교에서는 CompareTag() 를 사용하도록 한다.

객체의 tag 프로퍼티를 호출하는 것은 추가 메모리를 할당하며 복사를 하게된다.


- 모든 비교문에서 .equals()를 사용하도록 하자. == 구문으로 사용하면 임시적인 메모리가 나오게 되며 가비지 컬렉션의 먹이를 준다.


- 데이터 타입은 Class 대신 Struct 를 사용하여 만들어 주면 메모리 관리가 된다. 구조체는 메모리 관리를 Stack에서 하므로 GC에 들어가지 않는다.


- 즉시 해제시에는 Dispose를 수동으로 호출하게 되면 즉시 클린업된다.


- 임시 객체를 만들어내는 API를 조심해야한다.

GetComponents<T>, Mesh, Vertices, Camera.allCameras, 이런것들..


- 객체의 변경 사항에 대해 캐싱한다. 객체의 이동과 변형에 대한 처리를 캐싱해서 매프레임당 한번만 처리


- 컴포넌트 참조를 캐싱한다.

GetComponent()는 한번만 호출되며, 객체를 캐싱해서 사용한다.


- 콜백함수 안쓰는 것들을 제거해야한다. Start(), Update(), OnDestroy() 같은 것들은 비어있어도 성능에 영향을 끼치므로 지워주도록 하자.


4. 텍스쳐


- 텍스쳐를 압축 할때는 권작 압축 텍스쳐를 사용하도록 하자.

 -> 아이폰 : PVRCT

 -> 안드로이드 (Tegra) : DXT

 -> 안드로이드 (Adreno) : ATC

 -> 안드로이드 (공통) : ETC1


- 텍스쳐 사이즈는 2의 제곱이어야 한다.

 -> POT(Power of Two)

 -> POT가 아닌경우 POT 텍스쳐로 자동 변환 로딩이 된다.

 -> 900x900은 실제로는 1024 x 1024로 된다.


- 텍스쳐 아틀라스를 활용

 -> 텍스쳐 아틀라스로 최대한 묶어 사용 (NGUI Atlas 같은 사용법)

 -> UI 만 아니라, 같은 재질의 오브젝트를 묶어 사용하게 된다.


- 압축된 텍스쳐와 밉맵을 사용한다. (대역폭 최적화)


- 32bit가 아닌 16bit 텍스쳐 사용도 상황에 맞게 고려한다.



[사진 1] 보통 이렇게 최적화 하면 된다. (안드로이드)


5. Mesh


- Import 시에 언제나 "Optimize Mesh" 옵션을 사용한다.

 -> 변환 전/ 변환 후 버텍스 캐쉬를 최적화 해준다.


- 언제나 optimize Mesh Data 옵션을 사용한다.

 -> Player Setting > Other Settings

 -> 사용하지 않는 버텍스 정보들을 줄여 준다. (tangents, Normal, Color, ETC...)


6. 오디오


- 모바일에서 스테레오는 의미 없음

 -> 모두 92kb, 모노로 인코딩


- 사운드 파일을 임포트하면 디폴트로 3D 사운드 설정

 -> 2D 사운드로 변경


- 압축 사운드 (mp3, ogg), 비압축 사운드 (wav) 구별

 -> 비압축 사운드 : 순간적인 효과음, 이펙트

 -> 압축 사운드 : 배경 음악


7. 폰트 리소스 최적화


Packed Font를 사용

 -> R,G,B,A 채널에 저장하는 기법으로 메모리 용량을 1/4로 절약하도록 하자.

 -> 단 Packed Font는 단점이 너무 많다. 일반적으로 글씨에 그림자도 못 넣을 뿐더러 알파도 적용이 안된다. 그리고 NGUI Atlas 적용도 안됨.


8. 리소스


- ResourceLoadAsync() 함수는 엄청 느리다.

 -> 게임 레벨 로드시에 사용했을 경우, 일반 함수에 비해 수십배나 느리다.


9. 컬링


- Frustum Culling (프러스텀 컬링)

 -> Layer 별로 컬링 거리 설정이 가능 (NGUI 의 경우 Panel 에서 Smooth Culling 도 먹일 수 있다.)

 -> 멀리 보이는 중요한 오브젝트는 거리를 멀게 설정하고 중요도가 낮은 풀이나 나무등은 컬링 거리를 짧게 설정하여 컬링한다.


- Occlusion Culling (오클루젼 컬링)

 -> Window->Occlusion Culling 메뉴에서 설정 가능

 -> Occlusion Culling 이란 카메라에서 보이는 각도의 오브젝트 들만 렌더링 하는 기법을 뜻한다.


- Combine (오브젝트 통합)

 -> 드로우콜은 오브젝트에 설정된 재질의 셰이더 패스당 하나씩 일어남.

 -> 렌더러에 사용된 재질의 수 만큼 드로우 콜이 발생함.

 ->> Combine (통합)

  ->>> 성질이 동일한 오브젝트들은 하나의 메쉬와 재질을 사용하도록 통합

  ->>> Script 패키지 - CombineChildren 컴포넌트 제공

   ->>>> 하위 오브젝트를 모두 하나로 통합

  ->>> 통합하는 경우 텍스쳐는 하나로 합쳐서, Texture Atlas를 사용해야함.


- Batch


- Static Batch

 -> Edit > Project Setting > Player 에서 설정한다.

 -> 움직이지 않는 오브젝트들은 static으로 설정해서, 배칭이 되게 함.

 -> Static으로 설정된 게임 오브젝트에서 동일한 재질을 사용 할 경우, 자동으로 통합된다.

 -> 통합되는 오브젝트를 모두 하나의 커다란 메쉬로 만들어서 따로 저장한다. (메모리 사용량 증가)


- Dynamic Batch 

 -> 움직이는 물체를 대상으로 동일한 재질을 사용하는 경우, 자동으로 통합

 -> 동적 배칭은 계산량이 많으므로, 정점이 900개 미만인 오브젝트만 대상이 된다.


10. 라이팅


- 라이트 맵 사용

  -> 고정된 라이트와 오브젝트의 경우(배경) 라이트 맵을 최대한 활용

  -> 아주 빠르게 실행됨 (Per-Pixel Light 보다 2~3배)

  -> 더 좋은 결과를 얻을 수 있는 GI와 Light Mapper를 사용할 수 있다.


- 라이트 렌더 모드

 -> 라이팅 별로 Render Mode : Important / Not Important 설정이 가능하다.

 -> 게임에서 중요한 동적 라이팅만 Important 로 설정 (Per-Pixel Light)

 -> 그렇지 않은 라이트들은 Not Important로 설정한다.


11. Overdraw


- 화면의 한 픽셀에 두 번 이상 그리게 되는 경우 (Fill rate)

 -> DP Call의 문제만큼 Overdraw 로 인한 프레임 저하도 중요한 문제

 -> 특히 2D 게임에서는 DP Call 보다 더욱 큰 문제가 된다.


- 기본적으로 앞에서 뒤로 그린다.

 -> Depth testing 으로 인해서 오버드로우를 방지한다.

 -> 하지만 알파 블렌딩이 있는 오브젝트의 경우에는 알파 소팅 문제가 발생한다.


- 반투명 오브젝트의 개수의 제한을 건다.

 -> 반투명 오브젝트는 뒤에서부터 앞으로 그려야 한다. -> Overdraw 증가

 -> 반투명 오브젝트의 지나친 사용에는 주의해야 한다.


- 유니티의 Render Mode를 통해서 overdraw 확인이 가능하다.


12. 유니티 셰이더


- 기본 셰이더는 모바일용 셰이더 사용

 -> 기본 셰이더를 사용할 경우, 모바일용 셰이더를 사용한다.

  ->> Mobile > VertexLit는 가장 빠른 셰이더


- 복잡한 수학 연산

 -> pow, exp, log, cos, sin, tan 같은 수학 함수들은 고비용

 -> 픽셀별 그런 연산을 하나 이상 사용하지 않는 것이 좋다.

 -> 텍스쳐 룩업 테이블을 만들어서 사용하는 방법도 좋다.

 -> 알파 테스트 연산 (discard)는 느리다.

 -> 기본적인 연산 보다는 최적화 시키고 간략화시킨 공식들을 찾아서 사용할 수 있다.


- 실수 연산

 -> float : 32bit - 버텍스 변환에 사용. 아주 느린 성능 (픽셸 셰이더에서 사용은 피함)

 -> Half : 16bit - 텍스쳐 uv에 적합. 대략 2배 빠름

 -> fixed : 10bit - 컬러, 라이트 계산과 같은 고성능 연산에 적합. 대략 4배 빠르다.


- 라이트 맵을 사용하자.

 -> 고정된 라이트와 오브젝트의 경우 (배경) 라이트 맵을 최대한 활용.

 -> 아주 빠르게 실행됨 (Per-Pixel Light 보다 2~3배)

 -> 더 좋은 결과를 얻을 수 있는 GI와 Light Mapper 사용가능


13. Fixed Update 주기 조절


- FixedUpdate()는 Update와 별도로 주기적으로 불리는 물리엔진 처리 업데이트


- 디폴트는 0.02초 1초에 50번


- TimeManager에서 수정


- 게임에따라 0.2초 정도로 수정해도 문제 없음. 


14. 물리 엔진 설정


- Static Object

 -> 움직이지 않는 배경 물체는, static으로 설정


- 충돌체의 이동

 -> 리지트 바디가 없는 고정 충돌체를 움직이면, CPU 부하 발생

 -> 이럴 경우 리지드 바디를 추가하고, IsKinematic 옵션 사용


- Maximum Allowed Timestep 조정

 -> 시스템에 부하가 걸려, 지정된 시간보다 오래 걸릴 경우, 물리 계산을 건너뛰는 설정


- Solver Iteration Count 조정

 -> 물리 관련 계산을 얼마나 정교하게 할지를 지정. (높을수록 정교)

 -> Edit > Project Setting > Physics


- Sleep 조절

 -> 리지드 바디의 속력이 설정된 값보다 작을 경우, 휴면 상태에 들어감

 -> Physics.Sleep() 함수를 이용하면, 강제 휴면 상태를 만들기 가능


15. 물리 엔진 스크립트


- 래그돌 사용 최소화

 -> 래그돌은 물리 시뮬레이션 루프의 영역이 아니기 때문에, 꼭 필요할 때만 활성화 함.


- 태그 대신 레이어

 -> 물리 처리에서 레이어가 훨씬 유리하다. 성능과 메모리에서 장점을 가진다.


- 메쉬 콜라이더는 절대 사용하지 않는다.


- 레이캐스트와 Sphere Check 같은 충돌 감지 요소를 최소화 한다.


16. Tilemap Collision Mesh


- 2D 게임에서 타일맵의 Collision Mesh를 최적화 하라.

 -> Tilemap을 디폴트로 사용해서, 각 타일별로 충돌 메쉬가 있는 경우, 물리 부하가 커짐.

 -> 연결된 Tilemap을 하나의 Collision Mesh로 물리 연산을 최적화 하라



출처: http://vallista.tistory.com/entry/Unity-게임-최적화-기법 [VallistA]

반응형
Posted by blueasa
, |

유니티 함수로 네트워크 상태를 판단하려면 Application.internetReachability을 사용하여 알 수 있다.


Application.internetReachability

public static NetworkReachability internetReachability;

Description

Returns the type of Internet reachability currently possible on the device.
This property is mostly useful on handhelds to distinguish fast and cheap WiFi connection from carrier networking.

Note: Do not use this property to determine the actual connectivity. E.g. the device can be connected to a hot spot, but not have the actual route to the network. Non-handhelds are considered to always be capable of NetworkReachability.ReachableViaLocalAreaNetwork.

실제 연결을 확인하려면이 속성을 사용하지 마세요. 예를들면 device는 hot spot에 접속하지만, 실제의 네트워크 경로를 가질 수 없습니다.. Non-handhelds는 항상 NetworkReachability.Reachable 통해 LocalAreaNetwork를 할 수 있다고 간주합니다.
(http://docs.unity3d.com/ScriptReference/Application-internetReachability.html)

실제 서비스한 프로젝트에서 위 유틸을 사용했지만 많은 시행 착오 및 신뢰성이 떨어졌었다.

하여 가능하면 단말기 자체의 네트워크 상태정보를 가져오는것이 더 신뢰성이 높으므로
Navite코드를 통하여 Device의 상태정보를 가져올 수 있어야한다.

* AOS Native 관련 포스트
http://developer.android.com/training/basics/network-ops/managing.html
http://mainia.tistory.com/549

* IOS Native 관련 포스트
http://reysion.tistory.com/48





[출처] http://yeonhong.blogspot.kr/2015/04/unity3d.html



[참조] http://devkorea.co.kr/bbs/board.php?bo_table=m03_qna&wr_id=41570

반응형

'Unity3D > Tips' 카테고리의 다른 글

[링크] Unity 작업시 개인 Tip  (0) 2017.01.17
[펌] Unity3D :: 게임 최적화 기법  (0) 2017.01.17
[펌] UDID, UUID, 유니크 한 고정 값 완결  (0) 2017.01.04
[펌] 안드로이드 mcc mnc 읽어오기  (0) 2016.11.30
[펌] MCC/MNC  (0) 2016.11.30
Posted by blueasa
, |

UDID, UUID, 유니크 한 고정 값 완결



먼저 각 명칭에 대해 알아보도록 한다.



UUID - Universally Unique Identifire ( 시간, 공간을 이용하여 뽑아낸 128bit (중복되지 않는) 값 )

GUID - Globaly Unique Identifire ( UUID 와 같은 MS 에서 사용하는 값 )

UDID - Unique Device Identifire ( 기기 별 고유 식별 값 )


Vendor Identifier - 공급 업체 식별자

Advertising Identifier - 광고 식별자





기기별 고유값을 얻어오기 위해 이전 ( IOS 4 이하 ) 에서는 UDID 값을 가져와 사용 할 수 있었다.

그러나 이후 해킹 등에 취약하다는 이유로 사용 금지 시키고 IOS 5 부터는 UUID 를 사용하라고 권고하였다.


CFUUIDRef udid = CFUUIDCreate(NULL);
NSString *udidString = (NSString *) CFUUIDCreateString(NULL, udid);

위는 UUID 얻는 방법이다.  ( IOS 5 에서 )

IOS 6 에서는 아래와 같이 간편하게 얻을 수 있다.


NSString *uuid = [[NSUUID UUID] UUIDString];

이는 시간, 공간 값을 이용하여 128bit 를 이용해 얻어내여 중복 가능성이 없다고 한다.


얻어진 결과의 예제는 는 다음과 같다.

BE5BA3D0-971C-4418-9ECF-E2D1ABCB66BE


이를 사용하여, 유니크한 값으로 사용할 수는 있다.

다만 호출시마다 유니크한 값을 준다.


따라서 이 값으로 기기를 식별하거나 할 수 없다.


이를 사용하기 위해 키체인을 사용하여 저장하는 방법도 있다.

해당 방법은 아래와 같다.


접기

[UUID 키체인 저장 방법]

KeyChain API들은 Security.framework에 정의 되어 있는데 C함수로 되어 있고 API를 쓰는 것이 쉽지 않아 애플에서 쉽게 사용할 수 있게 KeychainItemWrapper 예제 클래스를 제공하고 있다.

일단 KeychainItemWrapper를 다운 받고 프로젝트에 추가해야 한다. (download)


    KeychainItemWrapper.h

    KeychainItemWrapper.m


아래는 UUID를 생성해서 KeyChain에 저장하는 함수 이다.

//처음에 UUID KeyChain에서 불러오는데 nil이라면 UUID 생성해서 KeyChain 저장한다.

//저장 후에 다시 함수를 호출 하면 저장된 값을 리턴한다.

- (NSString*) getUUID

{

    // initialize keychaing item for saving UUID.

    KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"UUID" accessGroup:nil];

   

    NSString *uuid = [wrapper objectForKey:(__bridge id)(kSecAttrAccount)];


    if( uuid == nil || uuid.length == 0)

    {

        // if there is not UUID in keychain, make UUID and save it.

        CFUUIDRef uuidRef = CFUUIDCreate(NULL);

        CFStringRef uuidStringRef = CFUUIDCreateString(NULL, uuidRef);

        CFRelease(uuidRef);

        uuid = [NSString stringWithString:(__bridge NSString *) uuidStringRef];

        CFRelease(uuidStringRef);

        

        // save UUID in keychain

        [wrapper setObject:uuid forKey:(__bridge id)(kSecAttrAccount)];

    }

    

    return uuid;

}


KeyChin에 대하여 설명을 하면..

KeychainItemWrapper를 사용하여 키체인에 값을 등록하게 되는데..

- (id)initWithIdentifier: (NSString *)identifier accessGroup:(NSString *) accessGroup


//내부 앱에서만 사용할 경우 

KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"UUID" accessGroup:nil];


//Keychain Group끼리 공유할 경우

KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"UUID" accessGroup:@"???????.com.yourcompany.GenericKeychainSuite"];


KeychainItemWrapper 인스턴스를 생성할 때 저장할 값을 구별할 이름(initWithIdentifier)과 accessGroup을 지정해야 한다.


- accessGroup은 KeyChain Group을 지정하는 것인데 nil이면 내부 앱에서만 사용하는 것이고 nil이 아닌 값을 사용하면 같은 Keychain Group을 사용하는 앱에서 공유가 가능하다.


- Keychain Group을 확인하는 방법은 xcode6에서는 프로젝트 > TARGETS 프로젝트 > capabilities > Keychain Sharing 에서 확인하면 된다. (xcode5, 6)


- (id)objectForKey:(id)key


//키체인에 저장된 값을 가져온다.

NSString *uuid = [wrapper objectForKey:(__bridge id)(kSecAttrAccount)];


- (void)setObject:(id)inObject forKey:(id)key


// 키체인에 저장한다.

[wrapper setObject:uuid forKey:(__bridge id)(kSecAttrAccount)]; 


- KeychainItemWrapper를 사용하여 데이터를 저장할 때 사용할 수 있는 상수는 아래와 같다.

  (https://developer.apple.com/library/ios/documentation/Security/Reference/keychainservices/index.html)

   1) kSecAttrAccount : Account 정보

   2) kSecAttrLabel : 라벨 정보

   3) kSecAttrDescription : 설명

   4) kSecValueData : Data


- 예를들어 암호화된 비밀번호를 저장하기 위해서 kSecValueData를 Key로 하고 암호화된 비밀번호를 InObject로 하면 된다. 로그인 이름을 저장한다면 kSecAttrAccount를 Key로 하고 저장하면 된다.


[참고]

http://10apps.tistory.com/archive/20130403

http://dev-metal.blogspot.kr/2010/08/howto-use-keychain-in-iphone-sdk-to.html



다음으로 

identifireForVender 의 설명이다.


1. 설치된 앱에서 호출 시 매번 같은 값을 리턴한다.

2. 다만 앱 재 설치 시 값이 바뀐다.

3. 같은 벤더를 사용하는 경우 값이 유지 된다,

    다만같은 벤더를 사용하는 앱을 모두 지울 경우 마찬가지로 값이 바뀐다.


따라서 identifireForVender 값도 영원한 기기 식별자로 사용 할 수 없다.






유니티의 SystemInfo.deviceUniqueIdentifier



Android 


 - readPhoneState 퍼미션이 설정되어있을 경우

   IMEI 값 리턴

   ex) 51F30A87-BBFA-128F-E915-C92391D2F164


 - readPhoneState 퍼미션이 설정되어있지 않을 경우

   AndroidID 값 리턴

   ex) 8127362567812635



IOS


 - IOS6 버젼 이전

   MAC_ADRESS 값을 해싱 하여 리턴


 - IOS7 버젼 이후

   ASIdentifierManager advertisingIdentifier 값을 리턴

   어떤 이유에서 이 값을 리턴 할 수 없는 경우 

   UIDevice identifierForVendor 를 리턴


[출처] http://flystone.tistory.com/149

반응형
Posted by blueasa
, |


TelephonyManager tel = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);

     String networkOperator = tel.getNetworkOperator();
     int mcc = 0, mnc = 0;
     if (networkOperator != null) {
         mcc = Integer.parseInt(networkOperator.substring(03));
         mnc = Integer.parseInt(networkOperator.substring(3));
     }

wifi 모델은 제대로 값을 읽지 못한다는 이야기가...;;;

Locale.getDefault().getCountry(); <- KR 을 리턴함.(세팅된 언어셋을 리턴하는 것이다...;;)
이걸 받아서 아래 링크쪽에 정의된 mcc랑 매핑을 시켜서 사용해야 할 것 같음

https://android.googlesource.com/platform/frameworks/opt/telephony/+/f39de086fddea9e9f6b8c56b04d8dd38a84237db/src/java/com/android/internal/telephony/MccTable.java

IP를 통해서 국가를 얻어올 수 있는 방법이 있다.



http://api.hostip.info/get_json.php <- 현재 접속한 ip address의 국가 정보를 리턴한다.
ex) 
{"country_name":"KOREA, REPUBLIC OF","country_code":"KR","city":"Seoul","ip":"210.182.216.2"}

자세한 내용은 아래 링크를 확인
http://codereview.stackexchange.com/questions/23102/getting-country-based-on-ip

국가 이름과 mcc를 매핑한 리스트는 아래와 같다.
<item>202,gr</item>
<item>204,nl</item>
<item>206,be</item>
<item>208,fr</item>
<item>212,mc</item>
<item>213,ad</item>
<item>214,es</item>
<item>216,hu</item>
<item>218,ba</item>
<item>219,hr</item>
<item>220,rs</item>
<item>222,it</item>
<item>225,va</item>
<item>226,ro</item>
<item>228,ch</item>
<item>230,cz</item>
<item>231,sk</item>
<item>232,at</item>
<item>234,gb</item>
<item>235,gb</item>
<item>238,dk</item>
<item>240,se</item>
<item>242,no</item>
<item>244,fi</item>
<item>246,lt</item>
<item>247,lv</item>
<item>248,ee</item>
<item>250,ru</item>
<item>255,ua</item>
<item>257,by</item>
<item>259,md</item>
<item>260,pl</item>
<item>262,de</item>
<item>266,gi</item>
<item>268,pt</item>
<item>270,lu</item>
<item>272,ie</item>
<item>274,is</item>
<item>276,al</item>
<item>278,mt</item>
<item>280,cy</item>
<item>282,ge</item>
<item>283,am</item>
<item>284,bg</item>
<item>286,tr</item>
<item>288,fo</item>
<item>289,ge</item>
<item>290,gl</item>
<item>292,sm</item>
<item>293,si</item>
<item>294,mk</item>
<item>295,li</item>
<item>297,me</item>
<item>302,ca</item>
<item>308,pm</item>
<item>310,us</item>
<item>311,us</item>
<item>312,us</item>
<item>313,us</item>
<item>314,us</item>
<item>315,us</item>
<item>316,us</item>
<item>330,pr</item>
<item>332,vi</item>
<item>334,mx</item>
<item>338,jm</item>
<item>340,gp</item>
<item>342,bb</item>
<item>344,ag</item>
<item>346,ky</item>
<item>348,vg</item>
<item>350,bm</item>
<item>352,gd</item>
<item>354,ms</item>
<item>356,kn</item>
<item>358,lc</item>
<item>360,vc</item>
<item>362,ai</item>
<item>363,aw</item>
<item>364,bs</item>
<item>365,ai</item>
<item>366,dm</item>
<item>368,cu</item>
<item>370,do</item>
<item>372,ht</item>
<item>374,tt</item>
<item>376,tc</item>
<item>400,az</item>
<item>401,kz</item>
<item>402,bt</item>
<item>404,in</item>
<item>405,in</item>
<item>410,pk</item>
<item>412,af</item>
<item>413,lk</item>
<item>414,mm</item>
<item>415,lb</item>
<item>416,jo</item>
<item>417,sy</item>
<item>418,iq</item>
<item>419,kw</item>
<item>420,sa</item>
<item>421,ye</item>
<item>422,om</item>
<item>423,ps</item>
<item>424,ae</item>
<item>425,il</item>
<item>426,bh</item>
<item>427,qa</item>
<item>428,mn</item>
<item>429,np</item>
<item>430,ae</item>
<item>431,ae</item>
<item>432,ir</item>
<item>434,uz</item>
<item>436,tj</item>
<item>437,kg</item>
<item>438,tm</item>
<item>440,jp</item>
<item>441,jp</item>
<item>450,kr</item>
<item>452,vn</item>
<item>454,hk</item>
<item>455,mo</item>
<item>456,kh</item>
<item>457,la</item>
<item>460,cn</item>
<item>461,cn</item>
<item>466,tw</item>
<item>467,kp</item>
<item>470,bd</item>
<item>472,mv</item>
<item>502,my</item>
<item>505,au</item>
<item>510,id</item>
<item>514,tl</item>
<item>515,ph</item>
<item>520,th</item>
<item>525,sg</item>
<item>528,bn</item>
<item>530,nz</item>
<item>534,mp</item>
<item>535,gu</item>
<item>536,nr</item>
<item>537,pg</item>
<item>539,to</item>
<item>540,sb</item>
<item>541,vu</item>
<item>542,fj</item>
<item>543,wf</item>
<item>544,as</item>
<item>545,ki</item>
<item>546,nc</item>
<item>547,pf</item>
<item>548,ck</item>
<item>549,ws</item>
<item>550,fm</item>
<item>551,mh</item>
<item>552,pw</item>
<item>602,eg</item>
<item>603,dz</item>
<item>604,ma</item>
<item>605,tn</item>
<item>606,ly</item>
<item>607,gm</item>
<item>608,sn</item>
<item>609,mr</item>
<item>610,ml</item>
<item>611,gn</item>
<item>612,ci</item>
<item>613,bf</item>
<item>614,ne</item>
<item>615,tg</item>
<item>616,bj</item>
<item>617,mu</item>
<item>618,lr</item>
<item>619,sl</item>
<item>620,gh</item>
<item>621,ng</item>
<item>622,td</item>
<item>623,cf</item>
<item>624,cm</item>
<item>625,cv</item>
<item>626,st</item>
<item>627,gq</item>
<item>628,ga</item>
<item>629,cg</item>
<item>630,cg</item>
<item>631,ao</item>
<item>632,gw</item>
<item>633,sc</item>
<item>634,sd</item>
<item>635,rw</item>
<item>636,et</item>
<item>637,so</item>
<item>638,dj</item>
<item>639,ke</item>
<item>640,tz</item>
<item>641,ug</item>
<item>642,bi</item>
<item>643,mz</item>
<item>645,zm</item>
<item>646,mg</item>
<item>647,re</item>
<item>648,zw</item>
<item>649,na</item>
<item>650,mw</item>
<item>651,ls</item>
<item>652,bw</item>
<item>653,sz</item>
<item>654,km</item>
<item>655,za</item>
<item>657,er</item>
<item>702,bz</item>
<item>704,gt</item>
<item>706,sv</item>
<item>708,hn</item>
<item>710,ni</item>
<item>712,cr</item>
<item>714,pa</item>
<item>716,pe</item>
<item>722,ar</item>
<item>724,br</item>
<item>730,cl</item>
<item>732,co</item>
<item>734,ve</item>
<item>736,bo</item>
<item>738,gy</item>
<item>740,ec</item>
<item>742,gf</item>
<item>744,py</item>
<item>746,sr</item>
<item>748,uy</item>
<item>750,fk</item>



[출처] http://nicelee.egloos.com/m/3025913

반응형
Posted by blueasa
, |

[펌] MCC/MNC

Unity3D/Tips / 2016. 11. 30. 15:47

MCC(Mobile Country Code)와 MNC(Mobile Network Code) 쌍은 통신사를 구분하기 위한 국가-통신사 코드 조합으로 우리나라에서 많이 쓰이는 CDMA, LTE 이외에 GSM, UMTS, TETRA 등에서도 사용된다. ITU-T에서 E.212를 통해 MCC/MNC를 제안했으며, 요즘은 보통 USIM에서 위 값의 조합을 가져올 수 있다.

안드로이드의 경우, SYSTEM PROPERTIES 중 하나인 gsm.operator.numeric에서 MCC+MNC 조합인 PLMN ID를 가져올 수 있다.

만약 3자리 이상이라면, 앞의 3자리가 MCC 그 나머지를 MNC로 보면 된다.  위의 23410의 경우, 영국(234)의 O2 통신사(10)이다.

MCC를 얻는 함수 예제는 아래와 같다.

그럼 MCC/MNC는 어디에 쓸까? 보통의 서비스들은 다국어 번역만 지원하고 사용자가 셋팅에서 언어를 바꿀 수 있게 하면 된다.

하지만, 구글 플레이 스토어나 애플의 앱스토어처럼 국가마다 다른 앱이나, 캠페인을 진행하고 싶은 경우 MCC를 참조할 수 있다. 그리고 간혹 통신사만의 캠페인을 진행하는 경우 MNC를 참조할 수 있다.

그런데 왜 번거롭게 USIM의 MCC/MNC를 이용해서 서비스를 다르게 보여주려고 할까? 사용자가 접속하고자 하는 국가를 고르면 되는 것 아닌가?

마켓의 경우는 앱을 다운로드 받기 때문에 단말이 네트워크에 연결되어 있어야 한다. Wi-Fi가 아니라면 통신사 망을 통해 데이터를 전송하기 때문에  USIM의 값이 중요하다. 그리고,  USIM을 구입할 나라라면 사용자가 더 거주할 확률이 높다고 판단하기 때문으로 보인다. 마지막으로, 신용카드 결제가 아닌 핸드폰 요금에 청구되는 소액결제의 경우(P-SMS와 캐리어 빌링이 대표적이다) USIM의 통신사에 따라 결제 여부가 달라지기 때문에 마켓에서는 USIM의 데이터를 더 신뢰한다.

클래시 오브 클랜처럼 게임을 만든다면 다국어 번역만 지원하고 사용자의 현재 언어를 파악하여 언어를 보여주거나 사용자가 셋팅에서 스스로 바꿀 수 있는 방법만 제공하면 되겠다. 애플이나 구글의 인앱결제들이 어떻게든 결제를 할 수 있게 고민할테니 말이다.

그 밖에

MCC/MNC는 USIM에 저장되어 있기 때문에, USIM을 따라다닌다. 단말을 구분하고 싶다면 IMEI 값을 참고하자. 2012년 5월부터는 완전히 공개된 정보가 되어 단말의 뒷면(배터리 탈착 부분)에서 확인할 수 있다.

참조


[출처] http://sunphiz.me/wp/archives/1047

반응형
Posted by blueasa
, |


[유니티5.x 기준 경로] 드라이브:\Users\{계정명}\AppData\Roaming\Unity\Asset Store-5.x




[참조] http://neojsm.tistory.com/8

반응형

'Unity3D > Tips' 카테고리의 다른 글

[펌] 안드로이드 mcc mnc 읽어오기  (0) 2016.11.30
[펌] MCC/MNC  (0) 2016.11.30
[펌] Borderless window in standalone player  (0) 2016.11.08
[펌] Disable Screen Auto Rotation on Unity3D  (0) 2016.11.03
[링크] Unity Technologies  (0) 2016.11.01
Posted by blueasa
, |
Best Answer

Answer by clunk47 

Of course it's easy. I do it by creating a shortcut or batch file that starts the exe, instead of running the exe file. For example, a batch file. This is just an example, so say our EXE name is RUN.EXE. You would open Notepad, type the following:

start RUN.EXE -popupwindow

Then File> Save as> and in the filename where it says .txt originally, just remove that and use an asterick and a bat extension (*.bat) Hit ENTER, then it will know you want to save as a bat file. Now just type in a name like Launcher.bat, don't forget to remove the asterick but keep the .bat extension. Now you would run this Launcher file. The argument -popupwindow is what allows your Unity Standalone EXE to run without borders :D




[출처] http://answers.unity3d.com/questions/13009/borderless-window-in-standalone-player.html

반응형
Posted by blueasa
, |

[추가]

Landscape은 아래 2개 변수를 제어


Screen.autorotateToLandscapeLeft

Screen.autorotateToLandscapeRight





Disable screen auto-rotation in a game in Unity. 

Option 1


Create a script that disables auto rotate to portrait and sets the orientation to landscape.

using UnityEngine;

public class CameraScript : MonoBehaviour {

    void Start() {
        DisableAutoRotation ();
    }

    public void DisableAutoRotation() {
        Screen.autorotateToPortrait = false;
        Screen.autorotateToPortraitUpsideDown = false;
        Screen.orientation = ScreenOrientation.Landscape;
    }
}



Create a game object to attach the script to. This can be any game object. You could also attach the script to the main camera in the scene either. When the game is run on hand held devices, the autorotation will be disabled.

Option 2


Another solution to this problem is to change this setting when building the project. 
Go to 
File -> Build Settings...




Click on Player Settings...


Click on Resolution and Presentations panel in the inspector. This will then expand and present more options.




In the Resolution and Presentation panel there are options for configuring the orientation.
First select the default Orientation. This is the orientation that the game will start in. 
You can configure what orientations are allowed when the game is being run. To do this, check or uncheck the required boxes for "Allowed Orientations for Auto Rotation".




[출처] http://andrewstutorialblog.blogspot.kr/2014/12/disable-screen-auto-rotation-on-unity3d.html

반응형
Posted by blueasa
, |