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

카테고리

분류 전체보기 (2221)
Unity3D (527)
Programming (463)
Unreal (4)
Gamebryo (56)
Tip & Tech (176)
협업 (32)
3DS Max (3)
Game (12)
Utility (106)
Etc (91)
Link (29)
Portfolio (19)
Subject (90)
iOS,OSX (36)
Android (3)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (1)
Memories (19)
Interest (37)
Thinking (34)
한글 (26)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (16)
Exercise (3)
나만의 맛집 (2)
냥이 (9)
육아 (2)
Total1,266,502
Today159
Yesterday385
Statistics Graph

달력

« » 2019.01
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    

공지사항

태그목록

오라클의 유료화 이슈로 OpenJDK를 설치하려는데

현재 버전(Unity v5.6.6f2)에서 좀 편하게 설치할 방법이 없을까 하다가 꼼수로 해놓은 방법 간단 정리해 놓습니다.



[유니티 버전] v5.6.6f2


[OpenJDK 간단(?) 설치 방법]

1. Unity2018.3 이상 버전을 설치


2. Unity2018.3의 Preferences에 보면 아래와 같이 기본 내장 OpenJDK가 설정 돼 있다.


3. Unity2018.3이 설치 된 곳에 가보면 위에 설명된 (AndroidPlayer/Tools/OpenJDK)를 찾을 수 있는데 정확한 경로는 아래와 같다.

   2018.3 설치 위치를 찾아서 아래 경로대로 찾아가자.

  [Unity2018설치경로] ...\2018.3.0f2\Editor\Data\PlaybackEngines\AndroidPlayer\Tools\OpenJDK


4. 3번의 위치까지 찾아가면 아래와 같이 OS별 폴더가 보인다.


5. 유니티 5.6.6의 Preferences에서 JDK를 아래처럼 해당 OS 폴더까지 패스로 골라준다.


나의 경우 Unity Hub를 깔아서 전체 경로는 아래와 같다.


[전체경로]

C:\Program Files\Unity\Hub\Editor\2018.3.0f2\Editor\Data\PlaybackEngines\AndroidPlayer\Tools\OpenJDK\Windows

Posted by blueasa

댓글을 달아 주세요


[링크]

https://orcacode.tistory.com/entry/Unity%EC%97%90%EC%84%9C-iPhone-X%EB%A5%BC-%EB%8C%80%EC%9D%91%ED%95%98%EB%8A%94-%EA%B0%84%ED%8E%B8%ED%95%9C-%EB%B0%A9%EB%B2%95


[플러그인]

https://github.com/rlatkdgus500/UnitySafeAreaController


Posted by blueasa

댓글을 달아 주세요

컬링(Culling)

  • 최종 화면에 영향을 미치지 않는 물체를 파악하고 이를 렌더링 대상에서 제외시켜 필요한 물체만 그리는 기법
  • 프러스텀 컬림(Frustum Culling)
    • 가장 기본적이면서도 효과가 좋은 방법
    • 카메라 영역내의 공간 정보만 살려두고 영역 외부에 설정된 정보는 모두 버림
    • 카메라에 프로젝트에 설정된 레이어별로 차단 거리(Per-Layer Cull Distances)를 지정하면 이 값을 사용해 레이어에 속한 게임 오브젝트들을 컬링함
  • 오클루젼 컬링(Occlusion Culling)
    • 기존의 절두체를 이용한 컬링 기법의 한계를 보완하고 효율적으로 공간 정보를 관리해 빠르게 렌더링을 수행할 수 있게 도와주는 기법
    • Unity의 Windows => Occlusion Culling 메뉴를 통해 설정
    • 오클루젼 컬링 제작방법
      1. 오클루젼 영역 설정
      2. 오클루젼 컬링 데이터 제작
      3. 최종 결과 시뮬레이션
    • 오클루젼 포털(Occlusion Portal)
      • 오클루젼 영역을 스크립트로 조절하는 기능

드로우 콜 배칭(Draw Call Batching)

  • 텍스쳐 아틀라스(Texture Atlas)를 사용하여 콜수를 줄임
  • 성질이 동일한 물체들을 하나의 메시와 재질을 사용하게 통합
    • 여러 게임 오브젝트의 메시를 하나의 메시로 통합해주는 CombineChildren 컴포넌트를 제공
    • 최상위 게임 오브젝트에 이 컴포넌트를 사용하면 자식 오브젝트들이 갖는 메시들을 분석한 후 재질별로 메시를 통합해 재가공함
    • 컴바인 메시(Combined Mesh)를 통한 작업시 주의할 점
      • 게임 오브젝트들을 통합하면 게임 오브젝트별로 움직일 수 없게 됨
      • 관련된 빛의 계산이 통합된 모든 메시를 대상으로 수행됨
    • 메터리얼(Materials)
      • 다른 텍스쳐에 있는 두개의 독립적인 메터리얼을 하나의 큰 텍스쳐로 결합 할 수 있음(텍스처 아틀라스)
      • 일단 텍스처를 동일한 아틀라스로 묶으면 단일 메터리얼로 사용할 수 있게 됨
    • 배칭(Batching)
      • 현재 씬의 상황을 판단해 자동으로 드로우 콜을 줄이게 최적화하는 기능

      • 정적 배칭 Static Batching (Pro required)

        • Static 옵션이 설정된 게임 오브젝트에서 동일한 재질을 사용하는 물체가 있는 경우 유니티는 이들을 자동으로 하나의 메시로 통합 관리함
        • 움직이지 않는 물체에 대해 지정만 하면 자동으로 수행
      • 동적 배칭 Dynamic Batching

        • 움직이는 물체를 대상으로 동일한 재질을 사용하는 경우 이를 판단해 자동으로 메시를 통합해 드로우 콜을 줄여주는 기능
        • 총 정점의 데이터 수가 900개 미만인 메시를 지닌 게임 오브젝트만을 대상으로 수행됨
        • 메시 데이터가 위치 외에도 노멀, UV, 라이트맵 UV 등 총 3개의 속성을 갖고 있는 경우 정점의 수가 225개를 넘으면 동적 배칭이 적용되지 않음

최적의 퍼포먼스를 위한 캐릭터 모델링(Modeling Characters for Optimal Performance)

  • 싱글 스킨 메쉬 렌더러 사용

    • 각 캐릭터에 스킨 메쉬 렌더러(class-SkinnedMeshRenderer)는 하나여야 합니다.
    • Unity는 시야 컬링 및 경계 볼륨의 업데이트를 사용하여 애니메이션을 최적화하고, 이러한 최적화는 하나의 애니메이션 컴포넌트 및 하나의 스킨 메쉬 렌더러를 사용하는 경우에만 활성화됩니다.
    • 모델의 렌더링 시간은 두개의 스킨 메쉬를 사용할때 하나의 스킨 메쉬를 사용 할 때보다 대략 2배 정도 이며, 여러개의 메쉬를 사용하여 실질적인 메리트가 있는 일은 드뭅니다.
  • 가능한 메터리얼을 적게 사용

    • 각 메쉬의 메테리얼의 수를 최대한 적게 해야 합니다.
    • 여러 메테리얼을 캐릭터에서 사용하는 이유는, 다른 부분에서 다른 쉐이더가 필요한 경우 뿐 입니다(예를 들면 눈 부분은 특수 쉐이더).
    • 그러나 캐릭터에서 두 개 또는 세 개의 메테리얼로 거의 모든 케이스에 충분 합니다.
  • 가능한 한 본(Bones)를 적게 사용

    • 전형적인 데스크톱 게임의 본 계층은 15개에서 60개 사이의 본을 사용합니다.
    • 본의 수가 적을수록 퍼포먼스가 좋아집니다.
    • 30개 정도의 본으로 데스크톱 플랫폼에서는 아주 좋은 품질을 얻을 수 있고, 모바일 플랫폼에서도 비교적 좋은 품질을 얻을 수 있습니다.
    • 이상적으로는 모바일 장치에서는 30개보다 적게 하고, 데스크톱 게임에서도 30개를 크게 초과하지 않도록 합니다.
  • 폴리곤 갯수를 적게 사용

    • 폴리곤 수는 필요한 품질 및 대상 플랫폼에 의존합니다.
    • 모바일 장치는 메쉬 당 300에서 1500 폴리곤으로 좋은 결과를 얻을 수 있으며, 데스크톱 플랫폼에서의 이상적인 범위는 1500에서 4000 정도입니다.
    • 반면, 게임에 많은 캐릭터가 있을 때 메쉬 당 폴리곤의 수를 줄일 필요가 있을 것 입니다.
    • 예를 들어, Half Life 2는 캐릭터에 2500 - 5000 삼각형 수였습니다.
    • 현재 PS3와 XBox 360의 최고 랭크 게임은 보통 캐릭터에 5000에서 7000 삼각형 수입니다.
  • 포워드 및 역운동학을 분리

    • 애니메이션이 임포트 될 때, 모델의 역운동학(IK) 노드는 포워드 운동학(FK)에 베이크(baked)된 결과로 Unity는 IK 노드가 전혀 필요 없습니다.
    • 그러나 모델에 남아있으면 애니메이션에 영향을 미치지 않음에도 불구하고 CPU 오버 헤드가 발생합니다.
    • 선호에 따라 Unity 또는 모델링 도구, 어느 것이든 중복 IK 노드를 제거할 수 있습니다.
    • 이상적으로는 IK 및 FK 계층을 모델링 시에 별도로 보관하여 필요할 때 IK 노드를 쉽게 제거할 수 있도록 해야 합니다.

렌더링 통계 창(Rendering Statistics Window) 확인

  • Time per frame and FPS
    • 하나의 게임 프레임을 처리 및 렌더링하는데 걸린 시간(프레임/초)
    • 이 숫자는 프레임 업데이트 및 게임 뷰의 렌더링에 걸린 시간만 포함되는 것에 유의
    • 에디터가 씬 뷰 인스펙터의 그리기 및 에디터 전용 작업을 수행하는데 걸린 시간은 포함되지 않음
  • Batches
    • “Batching” is where the engine attempts to combine the rendering of multiple objects into a chunk of memory in order to reduce CPU overhead due to resources switching.
  • Saved by batching
    • Number of batches that was combined. To ensure good batching, you should share materials between different objects as often as possible.
    • Changing rendering states will break up batches into groups with the same states.
  • Tris and Verts 그려진 삼각형과 정점의 수. 이것은 optimizing for low-end hardware에서 중요합니다.
  • Screen 화면 크기, 안티 앨리어싱 레벨 및 메모리 사용량.
  • SetPass 렌더링 패스의 수. 각 패스에 대해서 유니티 런타임은 CPU 오버헤드를 가져올 수 있는 새로운 쉐이더를 바인딩한다.
  • Visible Skinned Meshes 렌더링된 스킨 메쉬 수
  • Animations 재생 에니메이션 수

프레임 디버거(Frame Debugger)

  • 메뉴: Window > Frame Debugger
  • 매 프레임마다 그리는 오브젝트 정보를 보여줌

쉐이더 로딩타임 최적화(Optimizing Shader Load Time)

항상 포함하는 쉐이더와 미리 로딩해야 하는 쉐이더 집합을 설정하여 쉐이더 로딩시간을 효율적으로 관리해 줌

  • 항상 포함하는 쉐이더(Always Included Shaders)

    • Project Settings > Graphics > Always Included Shaders
  • 미리 로딩하는 여러가지 쉐이더 집합(Preloaded Shader Variant Collection)

    • 쉐이더 집합 생성

    • Assets > Create > Shader Variant Collection

    • 쉐이더 집합 미리 로딩 목록에 추가

    • Project Settings > Graphics > Preloaded Shaders

텍스처 캐시(Texture Cache)

  • 모바일의 경우 GPU 제조사에서 권장하는 텍스처 포멧을 사용하면 캐시 적중률이 높아져 속도의 향상을 얻게 되며, 특히 GPU의 성능이 약한 스마트폰 기기에서는 이러한 부분의차이가 큼
  • 플랫폼별 권장 텍스처 포멧
  • 안드로이드 텍스처 압축 지원
    • http://stackoverflow.com/questions/9148795/android-opengl-texture-compression/9514396#9514396
    • ETC1 (Ericsson texture compression)
      • This format is supported by all? Android phones.
      • But, It doesn't support an alpha channel, so can only be used for opaque textures.
    • PVRTC (PowerVR texture compression)
      • Supported by devices with PowerVR GPUs (Nexus S, Kindle fire ...)
    • ATITC (ATI texture compression)
      • Used in devices with Adreno GPU from Qaulcomm (Nexus One ...)
    • S3TC (S3 texture compression)
      • This texture compression is used in the NVIDIA chipset integrated devices (Motorola Xoom ...)
  • 안드로이드 Developer에 정의된 내용
    • https://developer.android.com/guide/topics/graphics/opengl.html#textures
    • ATITC (ATC) - ATI texture compression
      • GL_AMD_compressed_ATC_texture
      • GL_ATI_texture_compression_atitc
    • PVRTC - PowerVR texture compression
      • GL_IMG_texture_compression_pvrtc
    • S3TC (DXTn/DXTC) - S3 texture compression
      • GL_OES_texture_compression_S3TC
      • GL_EXT_texture_compression_s3tc
      • GL_EXT_texture_compression_dxt1
      • GL_EXT_texture_compression_dxt3
      • GL_EXT_texture_compression_dxt5
    • 3DC - 3DC texture compression
      • GL_AMD_compressed_3DC_texture
// Texture compression supported on Android
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
  Strings = gl.glGetString(GL10.GL_EXTENSIONS);
 
  if (s.contains("GL_IMG_texture_compression_pvrtc")) {
    // Use PVRTC compressed textures
  } else if (s.contains("GL_AMD_compressed_ATC_texture") ||
             s.contains("GL_ATI_texture_compression_atitc")) {
    // Use ATITC compressed textures
  } else if (s.contains("GL_OES_texture_compression_S3TC") ||
             s.contains("GL_EXT_texture_compression_s3tc")) {
    // Use DTX Textures
  } else {
    // Handle no texture compression founded
  }
}

텍스처 설정

  • Texture
  • Normal map
  • Editor GUI and Legacy GUI
  • Sprite (2D and UI)
  • Cursor
  • Reflection
  • Cookie
  • Lightmap
  • Advanced

텍스처 포멧지원 확인

텍스처 생성팁

오버드로우(Overdraw)

  • 물체가 겹쳐서 뒤에 있는 물체를 그린후에 앞에 있는 물체를 다시 그리면 겹치는 부분만큼 픽셀을 계산해서 그려야 함
  • 이렇게 특정 영역의 픽셀을 다시 그리는 것을 오버드로우라고 함
  • 불투명한 물체의 오버드로우를 줄이는 좋은 방법은 가장 큰 영역을 차지하는 물체를 먼저 그리게 설정하는 것

유용한 에셋





[출처] https://github.com/zzragida/UnityDocs/wiki/Graphics-Optimization

Posted by blueasa

댓글을 달아 주세요

다음과 같이, Application.OpenURL을 이용해서

내 App을 사용하는 유저의 버그 리포트나 기타 문의사항 등을 메일로 받아보도록 할 수 있습니다.


mailto : 받는 메일 주소

subject : 보낼 메일의 제목

body : 보낼 메일의 내용



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using UnityEngine;
 
public class EmailSender : MonoBehaviour
{
    public void OnClickEvent()
    {
        string mailto = "myapp.support@gmail.com";
        string subject = EscapeURL("버그 리포트 / 기타 문의사항");
        string body = EscapeURL
            (
             "이 곳에 내용을 작성해주세요.\n\n\n\n" +
             "________" +
             "Device Model : " + SystemInfo.deviceModel + "\n\n" +
             "Device OS : " + SystemInfo.operatingSystem + "\n\n" +
             "________"
            );
 
        Application.OpenURL("mailto:" + mailto + "?subject=" + subject + "&body=" + body);
    }
 
    private string EscapeURL(string url)
    {
        return WWW.EscapeURL(url).Replace("+""%20");
    }
 
}
 
cs



위의 OnClickEvent를 버튼에 달아서 사용하였습니다.

아래는 최근에 런칭한 로그(LOG) : 항해의 시작 이라는 게임 내 화면입니다.

이 프로젝트 런칭 준비하느라 통 블로그 활동을 못했네요 ... (핑계)





아래는, 위 사진의 '이메일 문의' 버튼을 눌렀을 때 나오는 화면입니다.

메일을 보내는 유저의 디바이스 모델과 OS도 알 수 있어서 도움이 되겠죠?








출처: http://minhyeokism.tistory.com/46 [programmer-dominic.kim]

Posted by blueasa

댓글을 달아 주세요

  1. 2018.09.19 04:21 신고 수요비  댓글주소  수정/삭제  댓글쓰기

    잘봤습니다 ^^

리모트 프로파일링(Remote profiling)은 다음의 스텝들에 의해서 iOS에 가능화 됩니다:

  1. iOS디바이스를 WiFi 네트워크에 연결하십시오. (로컬/임시(adhoc) WiFi 네트워크는 디바이스로부터의 프로파일링 데이터를 유니티 에디터로 보내기 위해서 프로파일에 의해 사용됩니다.)
  2. 유니티의 빌드 설정(build setting) 대화창의 "Autoconnect Profiler" 체크박스를 표시하십시오.
  3. 디바이스를 맥에 케이블로 부착하여 유니티 에디터의 "Build & Run"를 클릭하세요.
  4. 어플리케이션이 디바이스에서 실행할 때, 유니티 에디터의 프로파일러 창을 여십시오.(Window→Profiler)

_주의:_ 가끔 유니티 에디터는 디바이스로 자동 커넥트(autoconnect) 못할 수도 있습니다. 그런 경우는, 해당 디바이스를 선택하고 프로파일러 창에서 Active Profiler 드롭 다운 메뉴로부터 프로파일러 접속이 시작될 수 있습니다.



[출처] https://openwiki.kr/unity/profiler

Posted by blueasa

댓글을 달아 주세요

Using this method you can see if you are able to view the page you wanted or not by accessing the html of that page you can read it to see if you got redirected or not. this example uses www.google.com as it's check

  1. using System.Net;
  2. public string GetHtmlFromUri(string resource)
  3. {
  4. string html = string.Empty;
  5. HttpWebRequest req = (HttpWebRequest)WebRequest.Create(resource);
  6. try
  7. {
  8. using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse())
  9. {
  10. bool isSuccess = (int)resp.StatusCode < 299 && (int)resp.StatusCode >= 200;
  11. if (isSuccess)
  12. {
  13. using (StreamReader reader = new StreamReader(resp.GetResponseStream()))
  14. {
  15. //We are limiting the array to 80 so we don't have
  16. //to parse the entire html document feel free to
  17. //adjust (probably stay under 300)
  18. char[] cs = new char[80];
  19. reader.Read(cs, 0, cs.Length);
  20. foreach(char ch in cs)
  21. {
  22. html +=ch;
  23. }
  24. }
  25. }
  26. }
  27. }
  28. catch
  29. {
  30. return "";
  31. }
  32. return html;
  33. }

This is to call the function

  1. using System.Net;
  2. void Start()
  3. {
  4. string HtmlText = GetHtmlFromUri("http://google.com");
  5. if(HtmlText == "")
  6. {
  7. //No connection
  8. }
  9. else if(!HtmlText.Contains("schema.org/WebPage"))
  10. {
  11. //Redirecting since the beginning of googles html contains that
  12. //phrase and it was not found
  13. }
  14. else
  15. {
  16. //success
  17. }
  18. }



[출처] https://answers.unity.com/questions/567497/how-to-100-check-internet-availability.html

Posted by blueasa

댓글을 달아 주세요

<블로그 원문은 여기에서 확인하실 수 있으며, 블로그 번역 리뷰는 양찬석(Google)님이 참여해 주셨습니다.>


개발자분들과 만나 Firebase Analytics 관련된 이야기를 나누어보면, 다음과 같이 이야기하시는 경우가 종종 있습니다. "Firebase Analytics를 통해 앱 이벤트를 분석하면 좋겠지요. 하지만 지난 몇 년 동안 Google Analytics를 통해 데이터를 분석하고, 이를 튜닝하는데 많은 시간을 썼기 때문에, 새로운 도구를 사용하여 처음부터 다시 이러한 작업을 시작하고 싶지는 않네요."

그럼에도 Firebase Analytics의 몇몇 기능은 개발자 여러분의 일을 덜고 효과적인 앱 비지니스를 구축하는데 큰 도움이 될 수 있습니다. 예를들어 서버 구현 없이 특정 잠재 고객을 생성한 후 이를 대상으로 알림을 보내거나, Firebase 원격 구성(Remote Config)을 적용하기 위한 사용자 속성을 생성하는 것을 생각해볼 수 있습니다. 이러한 기능을 Google Analytics와 함께 활용할 수 있는 방법은 없을까요?

Google Analytics 기반 앱에 Firebase Analytics를 추가하는 데 관심이 있는 경우에 시도해볼 수 있는 몇 가지 전략을 살펴봅시다.

먼저 이벤트부터 검토

모바일 게임에서 매 라운드가 끝날 때마다 총 점수, 무찌른 적 수, 생존한 라운드 수의 세 가지 이벤트를 Google Analytics로 보낸다고 가정해봅시다. 다음과 같은 방법으로 Google Analytics에 값을 기록할 수 있습니다.

func recordGameOver() {
    let tracker = GAI.sharedInstance().defaultTracker
    let gameOverEvent = GAIDictionaryBuilder.createEvent(withCategory: "gameOver",
       action: "totalScore", 
       label: "", 
       value: myGameStats.totalScore as NSNumber)
    let enemiesBeatenEvent = GAIDictionaryBuilder.createEvent(withCategory: "gameOver",
       action: "enemiesBeaten", 
       label: "", 
       value: myGameStats.enemiesBeaten as NSNumber)
    let roundsSurvivedEvent = GAIDictionaryBuilder.createEvent(withCategory: "gameOver", 
       action: "roundsSurvived", 
       label: "", 
       value: myGameStats.roundsSurvived as NSNumber)
    tracker?.send(gameOverEvent.build() as [NSObject: AnyObject])
    tracker?.send(enemiesBeatenEvent.build() as [NSObject: AnyObject])
    tracker?.send(roundsSurvivedEvent.build() as [NSObject: AnyObject])
}

틀림없이 이런 질문을 하고 싶으실 겁니다. 바로 대답해 드리죠. 네, 맞습니다. 맞춤 측정기준(Custom Dimension)을 구성하고 하나의 이벤트로 이 작업을 수행할 수도 있습니다. 이런 방법으로 Google Analytics에서 플레이어의 최종 점수, 무찌른 적군 수, 생존한 라운드 수를 볼 수 있는 멋진 보고서를 만들 수 있습니다.

이제 이것을 Firebase Analytics 이벤트로 변환하는 방법에 대해 생각해봅시다. Google Analytics는 각각 하나의 연관된 값을 가진 계층적 이벤트를 중심으로 구성되지만, Firebase Analytics는 여기에서 한발 더 나아가 이벤트 매개변수로 함께 전달되는 다수의 연관된 키-값 쌍을 포함한 단일 이벤트를 기록합니다.

따라서 다음과 같이 Google Analytics 이벤트에서 Firebase Analytics 이벤트로 말 그대로 적절히 일대일 변환을 수행할 수 있습니다.

  FIRAnalytics.logEvent(withName: "gameOverTotalScore", 
      parameters: [kFIRParameterValue: myGameStats.totalScore as NSObject])
  FIRAnalytics.logEvent(withName: "gameOverEnemiesBeaten", 
      parameters: [kFIRParameterValue: myGameStats.totalScore as NSObject])
  FIRAnalytics.logEvent(withName: "gameOverTotalScore", 
      parameters: [kFIRParameterValue: myGameStats.totalScore as NSObject])

하지만 Firebase Analytics 환경에서는 이것을 다수의 맞춤 매개변수(Custom Parameter)를 포함한 하나의 이벤트로 기록하는 것이 더 자연스럽습니다.

  let finalStats = ["totalScore": myGameStats.totalScore as NSObject,
                    "enemiesBeaten": myGameStats.enemiesBeaten as NSObject,
                    "roundsSurvived": myGameStats.roundsSurvived as NSObject]
  FIRAnalytics.logEvent(withName: "gameOver", parameters: finalStats)

맞춤 측정기준 방식을 사용하는 개발자에게는 위 방법이 좀 더 익숙할 것 입니다.

두 번째 접근 방식을 선택하면, BigQuery를 사용하여 맞춤 매개변수를 분석해야 하지만, 이는 진지하게 데이타를 분석 하고 원하는 결과를 도출하기 위해서는 꼭 필요한 부분입니다. 이 과정 전체를 단계별로 설명하는 동영상을 참고하시면 도움이 될 듯 합니다.

올바른 방법으로 Firebase 추가하기

Firebase Analytics를 설치하고 실행하는 데 있어 가장 먼저 혼란을 느끼게 되는 사항 중 하나는 Google Analytics와 Firebase Analytics 모두 비슷한 설치 프로세스를 사용한다는 사실입니다.

예를 들어, iOS에서는 많은 개발자가 Google Analytics를 설치하고 실행하기 위해 Xcode 프로젝트에 GoogleService-info.plist 파일을 생성하고 추가했습니다. 하지만 Firebase Analytics를 올바로 구성하려면 또 하나의 GoogleService-info.plist 파일을 생성하고 Xcode 프로젝트에 추가하기도 해야 합니다. 이 두 가지를 모두 어떻게 수행할 수 있을까요?

이에 대한 대답은 콘솔에서 새 Firebase 프로젝트를 생성하는 것이 아니라 기존 Google Analytics 사용 프로젝트를 Firebase로 가져와서 Firebase를 설치하는 것입니다.

Firebase 프로젝트를 생성할 때 "Import Google Project" 버튼을 클릭하여 생성할 것입니다. Google Analytics 프로젝트를 선택한 다음 프로젝트 설정에서 GoogleService-info파일을 다시 다운로드하세요.

그러면 Firebase Analytics와 Google Analytics 양쪽에서 가져오는 plist 파일의 상위 집합을 얻게 될 것입니다. 내용을 살펴보면 새로운 Firebase 정보 전체와 함께 Google Analytics 추적 ID와 동일한 TRACKING_ID 항목이 보일 것입니다. 이전의 GoogleService-info파일을 이 새로운 파일로 바꾸고 나머지 Firebase 설치 프로세스를 진행하면 바로 사용할 수 있습니다.

Android에서는 이 프로세스가 기본적으로 동일하지만 .plist 대신 .json 파일을 사용하는 점만 다릅니다. 그리고 아마 Xcode 대신 Android Studio를 사용할 것입니다.

프로젝트를 올바로 설정했다고 가정하고, Google Analytics와 Firebase Analytics 모두에 원하는 데이터를 포함하려면 어떻게 해야 할까요? 다음과 같이 세 가지 옵션을 시도할 수 있습니다.

옵션 1: 2개의 Analytics SDK 사용

가장 간단한 시나리오는 단순히 Google Analytics 서비스를 계속 실행하면서 Firebase Analytics 추적도 앱에 추가하는 것입니다. 클라이언트에서 결과 코드는 다음과 같은 내용일 것입니다.

func recordGameOver() {
    // All the old code you had previously to record Google Analytics
    // … 
    // … So much code … 
    // … 
    // Now add the Firebase stuff
    let finalStats = ["totalScore": myGameStats.totalScore as NSObject,
                      "enemiesBeaten": myGameStats.enemiesBeaten as NSObject,
                      "roundsSurvived": myGameStats.roundsSurvived as NSObject]
    FIRAnalytics.logEvent(withName: "gameOver", parameters: finalStats)
}

개발자 관점에서 볼 때 왜 이런 해결 방법이 매력적인지 쉽게 상상할 수 있습니다. 구현이 매우 간단하고 위험도 낮기 때문이죠. 현재 Google Analytics 보고서의 문제가 생기지 않을까 걱정할 필요 없습니다. 모든 클라이언트 코드가 계속 Google Analytics를 항상 동일한 방식으로 호출하기 때문입니다. 추가로 Firebase Analytics도 호출하고 해당 시스템으로 데이터를 가져오면 됩니다.
그러나 이 해결 방법에는 몇 가지 단점이 있습니다. 첫째로, 두 가지 다른 분석 패키지로 데이터를 전송하게 되는데, 이는 일반적으로 클라이언트가 전보다 많은 네트워크 호출을 하게 됨을 의미합니다. 즉, 앱이 사용자의 모바일 데이터를 더 많이 사용하고 배터리 수명에 부정적인 영향을 미칩니다. 반면에 Firebase Analytics는 네트워크 호출을 수행하는 문제에 관한 한 상당히 보수적인 경향이 있으므로, 아주 큰 문제가 되지는 않을 것 입니다.

아마도 더 큰 단점은 모든 곳에서 분석 코드가 중복된다는 사실일 것입니다. 이미 분석 호출을 구현 세부 정보를 숨기는 별도의 메서드로 추상화했다면 이는 별로 중요한 문제가 아닙니다. 이제 이 하나의 메서드에 Firebase를 그냥 추가할 것입니다. 그러나 추상화하지 않았다면 이 코드를 앱 전체에 추가한다는 아이디어는 개발자에게 그다지 설득력 있게 들리지 않을 것입니다. 그래서 고려할 수 있는 또 다른 옵션이 있습니다.

옵션 2: Google 태그 관리자를 사용하여 어디에서나 이벤트 보고

Google 태그 관리자는 제 개인적으로 '언젠가 따로 시간을 내어서라도 꼭 배우고 싶은' 도구 목록에 항상 올라있는 멋진 만능 도구입니다. 그만한 이유가 있습니다. Google 태그 관리자가 제공하는 정말로 멋진 기능 중 하나는 발신되는 Firebase Analytics 이벤트에서 Google 애널리틱스는 물론 타사 애널리틱스 제공업체에게도 동일한 이벤트를 보고할 수 있다는 점입니다.
이 솔루션의 좋은 점은 클라이언트에서 한 세트의 분석-보고 코드만 필요하다는 사실입니다. 이 예시에서는 Google Analytics 호출을 완전히 제거할 수 있는 훨씬 간단한 구현 방법을 제시합니다.

func recordGameOver() {
    let finalStats = ["totalScore": myGameStats.totalScore as NSObject,
                      "enemiesBeaten": myGameStats.enemiesBeaten as NSObject,
                      "roundsSurvived": myGameStats.roundsSurvived as NSObject]
    FIRAnalytics.logEvent(withName: "gameOver", parameters: finalStats)
    // That's it!
}

Google 태그 관리자를 사용하여 이러한 이벤트를 Google Analytics에 보고하려면 CocoaPods/Gradle을 통해 라이브러리를 설치하고 프로젝트에 .json 파일을 추가해야 합니다. 이 모든 작업은 클라이언트 측에서 진행됩니다. 대부분의 작업은 태그 관리자 콘솔 내에서 수행됩니다.

태그 관리자 콘솔에서 Google Analytics로 보낼 모든 값에 대해 Firebase 이벤트 매개변수를 생성하고 싶을 것입니다. 이 예시에서는 totalScore, enemiesBeaten 및 roundsSurvived에 대한 값이 필요합니다.
다음으로, 대응시키려는 각각의 Firebase Analytics 이벤트에 대한 트리거를 생성할 것입니다. 이 경우에는 "gameOver"라는 이벤트 이름이 나타날 때마다 발생하는 트리거를 생성하려고 합니다.

마지막으로, Google Analytics(Google 태그 관리자 내에서는 Universal Analytics로 지칭함)로 이벤트를 보내 이러한 트리거에 응답하는 태그를 생성할 것입니다. AppsFlyer, Kochava, Tune 등과 같은 서비스로 이벤트를 보낼 수도 있습니다.

솔직히 기회만 된다면 보통은 코드를 적게 작성하는 것이 좋기 때문에 저는 이 접근 방식을 좋아합니다. 이 접근 방식을 취하면 일부 이벤트를 다른 곳은 말고 Google Analytics로만 보고하거나, (일부 이벤트를 Firebase Analytics에만 보고하기 시작하려는 경우) 앱이 출시된 이후라도 Firebase Analytics 이벤트를 Google Analytics로 보고하는 방법을 변경할 수 있는 유연성을 누릴 수도 있습니다.

한 가지 주목할 중요한 점은 현재 Firebase Analytics와 Google 태그 관리자를 함께 사용하여 전자 상거래 데이터를 Google Analytics에 보낼 수는 없다는 사실입니다. 담당 팀에서 이 문제를 해결하기 위해 노력하고 있지만 그동안은 Google Analytics에서 전자 상거래 데이터가 필요한 경우 다른 옵션 중 하나를 고려하거나 전자 상거래 이벤트를 Google 애널리틱스로 바로 보내도록 코드에 그냥 둘 수 있습니다.

위에서 언급했듯이, 클라이언트로부터 중복된 보고 분석 호출을 계속 수행한다는 단점도 있습니다. 또한, 모든 트리거, 이벤트 및 태그를 Google 태그 관리자 패널에 추가하는 데 많은 시간을 써야 합니다. 그러나 이보다 더 나쁜 상황도 생각할 수 있습니다. 클라이언트에서 2개의 분석 SDK를 실행한다는 아이디어에 반대하는 입장이라면 어떻게 해야 할까요? 그렇다면 다른 어떤 옵션을 사용할 수 있을까요? 당연한 질문입니다!

옵션 3: BigQuery를 사용하여 모든 항목 병합

고려할 수 있는 또 다른 옵션은 클라이언트에서 Google Analytics를 Firebase Analytics로 완전히 대체한 다음에 백엔드에서 BigQuery를 사용하여 이전 Google Analytics 데이터를 새 Firebase Analytics 데이터와 병합하는 것입니다.


이 솔루션은 이미 Google Analytics 360 고객으로서 현재 대부분의 맞춤 보고서를 BigQuery를 사용하여 작성하는 경우에만 적합하다는 점은 당연합니다. 이런 경우라면 BigQuery 쿼리를 업데이트하여 두 데이터 소스에서 모두 데이터를 가져오는 것이 합리적인 옵션일 수 있습니다.

앞서 제시한 예로 다시 돌아가서, 다음과 같은 쿼리를 실행하여 BigQuery 내에서 '일일 평균 최종 점수' 보고서를 이미 생성해오고 있다고 가정해봅시다.

SELECT
  AVG(hit.eventInfo.eventValue)
FROM
  `my_awesome_app.ga_sessions_20170123`,
  UNNEST(hits) AS hit
WHERE
  hit.eventInfo.eventCategory = "gameOver"
  AND hit.eventInfo.eventAction = "totalScore"
이제 Firebase Analytics로 전환합시다. 클라이언트에서 Firebase Analytics에 대해서만 호출하는 이전 예시의 간단한 구현을 사용할 수 있습니다.
func recordGameOver() {
    let finalStats = ["totalScore": myGameStats.totalScore as NSObject,
                      "enemiesBeaten": myGameStats.enemiesBeaten as NSObject,
                      "roundsSurvived": myGameStats.roundsSurvived as NSObject]
    FIRAnalytics.logEvent(withName: "gameOver", parameters: finalStats)
    // That's it!
}
그리고 시간에 따라 무찌른 평균 적군 수를 보려면 두 데이터 세트를 병합해야 합니다. 이를 위한 SQL은 다음과 비슷한 내용일 것입니다.

SELECT
  COUNT(*),
  AVG(total_score) AS average
FROM (
  SELECT
    event_param.value.int_value AS total_score
  FROM
    `firebase-project.com_example_awesome_app.app_events_20170123`,
    UNNEST(event_dim) AS event,
    UNNEST(event.params) AS event_param
  WHERE
    event.name = "gameOver"
    AND event_param.key = "totalScore"
  UNION ALL
  SELECT
    hit.eventInfo.eventValue AS total_score
  FROM
    `my_awesome_app.ga_sessions_20170123`,
    UNNEST(hits) AS hit
  WHERE
    hit.eventInfo.eventCategory = "gameOver"
    AND hit.eventInfo.eventAction = "totalScore" )

분명히 이것은 아주 간단한 예시입니다. 수행하려는 작업과 데이터 구조에 따라 상황이 더욱 빠르게 복잡해질 수 있습니다. 그러나 Google 클라우드 빅 데이터 블로그 게시물 작성에 참여 중인 (훨씬 똑똑한) 몇몇 동료가 이처럼 정교한 몇 가지 쿼리에 대한 글을 써서 올릴 것입니다. 그러니 계속 저희 블로그를 지켜봐 주세요!
이미 Google Analytics에 맞게 설정되어 있는 앱에 Firebase Analytics를 추가하는 방법에 대한 몇 가지 지침이 있습니다. 또는 그런 점에서는 다른 분석 플랫폼도 마찬가지입니다. 일단 설정을 마치면 Firebase Analytics 데이터를 사용하는 몇 가지 Firebase 기능을 시험해보는 것이 좋습니다. 특정 사용자 속성을 가진 사용자에게 새로운 원격 구성 설정을 제공하거나 자신이 만든 Firebase Analytics Audience에 알림을 보내보세요. 더 많은 Firebase Analytics 이벤트를 자유롭게 추적해 보세요. 앱 사용자 수에 관계없이 무료이고 무제한이므로 맘껏 이용하세요. 더욱 매력적인 도구와 기능이 계속 추가될 예정임으로 개발하려는 모바일 앱에 지금 바로 Firebase Analytics를 추가하더라도 그리 때이른 일이 아닐 것입니다. 한번 시도해보세요!



[출처] https://developers-kr.googleblog.com/2017/03/how-do-i-add-firebase-analytics-to-app.html

Posted by blueasa

댓글을 달아 주세요

앱 실행 시, 타 앱(멜론이나 벅스뮤직 등)의 백그라운드에서 재생되는 음원을 끄게 할 수 없냐고 말이나와서 권한 문제로 안될 줄 알았는데..

유니티 셋팅에 보니 PlayerSettings-Other Settings에 Mute Other Audio Sources 옵션이 있다.


켜주니 타 앱 사운드가 잘 꺼진다.


  [Android 주의사항]

Android Marshmallow (6.0) 이상은 READ_PHONE_STATE permission을 추가해줘야 된다고 한다.




[출처] https://stackoverflow.com/questions/39080989/unity-app-stops-background-music


[참조] https://docs.unity3d.com/ScriptReference/PlayerSettings-muteOtherAudioSources.html

[참조] http://jwandroid.tistory.com/153

Posted by blueasa

댓글을 달아 주세요

[TroubleShooting]


[에러메시지]

NotSupportedException: .... System.Net.WebRequest.GetCreator (System.String prefix) System.Net.WebRequest.Create (System.Uri requestUri)


PC/iOS에서는 잘 되는데 Android에서 위와 같은 NotSupportedException이 난다.(현재 Unity v5.6.5f1)

검색해보니 게임코디에 아래와 같은 답변을 해주신 분이 있다.



  비회원: 
kimsama

NotSupportedException: .... System.Net.WebRequest.GetCreator (System.String prefix) System.Net.WebRequest.Create (System.Uri requestUri) 모바일에서 위의 에러로 인해 HttpWebReaquest 를 사용하지 못하는 경우라면 여기 링크의 내용 참고하시기 바랍니다. http://www.vovchik.org/blog/13001 간단하게 우회하는 방법이 나와 있습니다.

[출처] http://lab.gamecodi.com/board/zboard.php?id=GAMECODILAB_QnA_etc&page=2&sn1=&divpage=1&sn=off&ss=on&sc=on&select_arrange=headnum&desc=asc&no=2617



그래서 링크(http://www.vovchik.org/blog/13001)에서 말해준 대로 Wrapping을 해서 Android에서 돌려보니 잘된다!!

(kimsama님 감사합니다!)


내가 추가 및 수정한 소스는 아래와 같다.


// Wrapper Class
using System;
using System.Net;

public class HttpRequestCreator : IWebRequestCreate 
{
	public WebRequest Create(Uri uri)
	{
		return new HttpWebRequest(uri);	
	}
}


    //Get size of the asset
    HttpRequestCreator cHttpRequestCreator = new HttpRequestCreator();            // modify
    System.Net.WebRequest req = cHttpRequestCreator.Create(new Uri(assetURL));    // modify
    req.Method = "HEAD";

    float ContentLength;
    using (System.Net.WebResponse resp = req.GetResponse())
    {
        float.TryParse(resp.ContentLength.ToString(), out ContentLength);
    }

    while (!download.isDone)
    {
        if (progressBar != null)
	    {
            progressBar.LabelInformations = "Downloading Assets";
            progressBar.Progress = download.progress;
            progressBar.AssetSize = ContentLength / 1000000; //(Mb)
	    }
	    yield return null;
    }






- CDN에 있는 파일 사이즈를 어떻게 알 수 없나 하고 찾다가 테스트 해보고 잘 되길래 올려 놓음.

  (PC/iOS는 잘되는데 Android가 에러나서 위와 같이 고침)

    1. //Get size of the asset
    2. System.Net.WebRequest req = System.Net.HttpWebRequest.Create(assetURL);
    3. req.Method = "HEAD";
    4. float ContentLength;
    5. using (System.Net.WebResponse resp = req.GetResponse())
    6. {
    7. float.TryParse(resp.ContentLength.ToString(), out ContentLength);
    8. }
    9. while (!download.isDone)
    10. {
    11. if (progressBar != null)
    12. {
    13. progressBar.LabelInformations = "Downloading Assets";
    14. progressBar.Progress = download.progress;
    15. progressBar.AssetSize = ContentLength / 1000000; //(Mb)
    16. }
    17. yield return null;
    18. }


[출처] https://answers.unity.com/questions/1035361/get-size-of-an-online-assetbundle-and-progress-in.html




Posted by blueasa

댓글을 달아 주세요

You can check against UnityEngine.iOS.Device.generation

Note that you'll need Unity 2017.2 or higher to detect iPhone X. 

Unity 5.6.5f1 also seems to support the iPhoneX enum, even though it's not listed in the 5.6 docs. 

  1. bool deviceIsIphoneX = UnityEngine.iOS.Device.generation == UnityEngine.iOS.DeviceGeneration.iPhoneX;
  2. if (deviceIsIphoneX) {
  3. // Do something for iPhone X
  4. }


To check against iPad, you could probably go:

  1. bool deviceIsIpad = UnityEngine.iOS.Device.generation.ToString().Contains("iPad");
  2. if (deviceIsIpad) {
  3. // Do something for iPad
  4. }


[출처] https://answers.unity.com/questions/1432365/how-to-detect-iphone-x-or-ipad-using-iosdevicegene.html

Posted by blueasa

댓글을 달아 주세요