Unity3D 사용시 특정 디바이스에서 Audio 재생이 지연되는 문제에 대해…

개발 중인 게임이 현재 가지고 있는 테스트 폰 중에서 유독 L전자 핸드폰에서 AudioClip을 재생할 때에 재생 명령이후 실제 소리가 들릴 때까지 약간의 지연이 생기는 문제가 발생하고 있네요.

이런 저런 자료를 찾다보면

Unity3D 자체가 조금의 지연을 일으킨다는 이야기가 좀 나오는데요.

일부에서는 android.media.SoundPool 을 사용해서 Java 단에서 AudioClip 재생을 하도록 구현하면 조금 나아진다는 이야기들이 있습니다.

조금 번거롭긴 합니다만… 한번 만들어두면 이후 프로젝트에서도 써 먹을 수 있고 하니
한번 참고해 보세요.

참고자료)
SoundPool 문서
Unity3D관련 글

AlarmManager로 Broadcast 알람 구현하기

Android API level 16을 기준으로 합니다. (4.1.x)

우선 알람 매니저를 가져오는 방법

AlarmManager alarmManager = (AlarmManager)this.getApplicationContext().getSystemService(Context.ALARM_SERVICE);

알람 매니저에 알람을 설정하는 방법

long alarmTime = System.currentTimeMillis() + 5 * 1000; // 지금부터 5초 뒤
alarmManager.set(AlarmManager.RTC_WAKEUP, alarmTime, createPendingIntent("kr.pe.bspfp.alarm", 123, "test"));

알람 매니저에서 알람을 해제하는 방법

alarmManager.set(createPendingIntent("kr.pe.bspfp.alarm", 123, null));

PendingIntent 생성

private PendingIntent createPendingIntent(String action, int requestCode, String msg) {
	Intent intent = new Intent(action);
	if (msg != null) {
		Bundle bundle = new Bundle();
		bundle.putInt("RequestCode", requestCode);
		bundle.putString("Message", msg);
		intent.putExtra("Params", bundle);
	}
	return PendingIntent.getBroadcast(this.getApplicationContext(), requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}

set에서 사용하는 타입 설명

  • AlarmManager.ELAPSED_REALTIME
    부팅 후 지난 시간이 설정된 시간과 같아지면 알림
  • AlarmManager.ELAPSED_REALTIME_WAKEUP
    AlarmManager.ELAPSED_REALTIME와 동일, 알림시 장치를 깨우는 것이 차이점
  • AlarmManager.RTC
    UTC 기분 밀리초 시간, System.currentTimeMillis() 하면 나오는 그 시간
  • AlarmManager.RTC_WAKEUP
    AlarmManager.RTC와 동일, 알림시 장치를 깨우는 것이 차이점

AlarmManager.cancel()에 대해

PendingIntent에 설정된 Inten의 filterEquals()가 true 인 대상을 취소
위 예제에서는 같은 action과 request code를 가지면 취소되었음

PendingIntent.FLAG_…

  • PendingIntent.FLAG_CANCEL_CURRENT
    중복된 PendingIntent가 존재하면 취소하고 새로 생성
  • PendingIntent.FLAG_NO_CREATE
    중복된 PendingIntent가 존재하면 생성하지 않고 null 반환
  • PendingIntent.FLAG_ONE_SHOT
    일회용 PendingIntent
  • PendingIntent.FLAG_UPDATE_CURRENT
    중복된 PendingIntent가 존재하면 생성하지 않고 extra 데이터만 변경

페이스북에 내 앱을 소개하는 링크를 공유해보자

Android에서의 방법은 크게 2가지입니다.



  1. Facebook SDK를 사용한다.

  2. ACTION_SEND를 이용한다.

Facebook SDK를 사용하면 친구 목록을 가져오거나 여러가지 페이스북의 기능을 사용할 수 있습니다.
그러나 조금 무거운 감이 없지 않군요. 작업해야 할 것도 많아지고
만약 간단하게 게임 소개 링크 정도만 공유를 하는 것이라면 2번 방법을 추천합니다.


우선 ACTION_SEND를 보내는 방법 (페이스북 개발자 사이트의 공식적인?? 방법)

String mySharedLink = “https://bspfp.pe.kr”;
String mySubject = “BSPFP Blog”;
int mySharedLink = 1001;
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType(“text/plain”);
intent.putExtra(Intent.EXTRA_SUBJECT, mySubject); // 페이스북은 무시하는 정보이지만 트위터나 Mail 등등에서는 필요한 항목
intent.putExtra(Intent.EXTRA_TEXT, mySharedLink);

// 공유할 대상을 고르는 리스트를 출력
startActivityForResult(Intent.createChooser(intent, “Share Chooser Title”), myRequestId);




그런데 이 방법으로는 다른 ACTION_SEND를 처리하는 앱이 주욱 나와서 영…
조금 수정하는 방법

String mySharedLink = “https://bspfp.pe.kr”;
String mySubject = “BSPFP Blog”;
int mySharedLink = 1001;
String[] recipients = new String[]{“e-mail address”};
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType(“text/plain”);
intent.putExtra(Intent.EXTRA_SUBJECT, mySubject); // 페이스북은 무시하는 정보이지만 트위터나 Mail 등등에서는 필요한 항목
intent.putExtra(Intent.EXTRA_TEXT, mySharedLink);

// 이 부분부터가 달라지는 부분
boolean fbAppFound = false;
List<ResolveInfo> resolveInfoList = getPackageManager().queryIntentActivities(intent, 0);
for (ResolveInfo info : resolveInfoList) {
// 페이스북 패키지명이 com.facebook.katana 인데 바뀔 가능성은 거의 0
// 페이스북 메신저 앱은 com.facebook.orca
if (info.activityInfo.packageName.toLowerCase().startsWith(“com.facebook.katana”)) {
intent.setPackage(info.activityInfo.packageName);
fbAppFound = true;
break;
}
}

// 페이스북이 없으면 Web을 통해 공유 (또는 GMail), 그것도 없으면 그냥 Chooser 발동!!!
if (!fbAppFound) {
if (usingFacebookWeb) {
// 페이스북 웹을 통해 공유
String sharerUrl = “https://www.facebook.com/sharer/sharer.php?u=” + mySharedLink;
intent = new Intent(Intent.ACTION_VIEW, Uri.parse(sharerUrl));
} else {
// GMail 로 보내기
boolean gmailAppFound = false;
for (ResolveInfo info : resolveInfoList) {
// GMail 패키지 찾기
if (info.activityInfo.packageName.contains(“com.google.android.gm”)
|| info.activityInfo.name.toLowerCase().contains(“gmail”)) {
intent.setPackage(info.activityInfo.packageName);
gmailAppFound = true;
break;
}
}

if (gmailAppFound) {
intent.putExtra(android.content.Intent.EXTRA_EMAIL, recipients);
} else {
startActivityForResult(Intent.createChooser(intent, “Share Chooser Title”), myRequestId);
return;
}
}
}

startActivity(intent);




참고용 소스로 그대로 사용하시면… 망합니다. ㅋㅋ


그럼 이어서


링크에 나타나는 내용을 바꿔보겠습니다.
[페이스북 Open Graph 디버깅 페이지] 를 들어가서 공유할 링크를 입력하고 새로 Fetch !!! 를 하면..
공유할 화면에서 보게될 상태를 미리 확인할 수 있습니다.
그럼 해당 URL이 응답하는 HTML 헤더에 Open Graph Meta 데이터를 넣어주시면 원하는 모습과 내용의 링크 공유가 완성됩니다.
Meta 태그에 들어가는 내용은 [The Open Graph protocol] 에서 확인할 수 있습니다.


그럼 마지막! 팁 하나
페이스북은 Open Graph 정보를 아래와 같은 규칙으로 가져옵니다. [페이스북 개발자 사이트 참고]



  1. HTTP redirect

  2. <link rel=”canonical” href=”…” />

  3. <meta property=”og:url” content=”…” />

이 순서대로 이동하다 마지막이 되는 페이지의 헤더에서 meta 태그를 가져옵니다.
따라서 구글 플레이 스토어로 이어지는 URL을 설정하면? 망합니다.
그럼 어떻게 해야 원하는 og:…을 설정하면서 마켓 URL로 이동할 수 있을까요?


<body … onload=’location.href = “http://www.example.com”‘>

 


이런 식으로 body에 넣어주세요.


보너스!!!
이미지가 바뀌었는데 페이스북에 적용이 안된다면… 위에 설명에 나온 디버깅 페이지에서 새로 Fetch 하면 됩니다.
디버깅 하느라 이왕 가져온 데이터를 버리기 아까운 페이스북이 캐시 업데이트를 하거든요.


즐거운 개발 행복한 인생! BS 였습니다.

Android Studio에서 JAR 라이브러리 만들기

방법1) Java Library 모듈을 추가해서 Application에 Dependency 걸어주고 빌드하면 나오는 JAR 파일을 사용한다.
문제점: 안드로이드 SDK에 포함되어 있는 Java 클래스 사용이 안됨


방법2) Android Library 모듈을 추가해서 Application에 Dependency 걸어주고 빌드하면 나오는 AAR 파일을 압축을 풀어서 classes.jar 파일을 사용한다.
문제점: 빌드 자동화하기가 힘들다.


방법3) 그냥 구버전 IDE인 Eclipse를 계속 사용한다.
문제점: 써보면 새로운 IDE가 얼마나 더 편리해졌는지 실감나는데 구버전을 쓰려니 화가 나서 안되겠음.

Eclipse에서 Wifi로 디버깅하기


  1. 스마트폰 네트워크 설정
    PC와 같은 네트워크에 폰의 Wifi가 연결되어 있어야 합니다.
    고정 IP를 할당하는 것이 정신 건강에 좋습니다.

  2. 장치를 USB에 연결
    연결해야 아래 명령이 핸드폰에 전달 됩니다.

  3. ADB로 tcp 연결 설정
    adb tcpip 5555

  4. ADB로 장치에 접속
    adb connect <폰 IP>:5555

  5. 이제 USB 연결이 없어도 됩니다.

  6. Eclipse에서 Run > Debug Configurations > Target 에 들어가서
    Always prompt to pick device 또는 Manual 을 선택합니다.

  7. 디버깅을 하면 장치를 고르는 화면이 나오는데 여기에서 네트워크로 접속한 장치를 선택합니다.

  8. 연결을 끝내고 다시 USB로 전환할 때에는
    adb -s <폰 IP>:5555 usb

참 쉽죠?
참 편리합니다.

갤럭시 S2 다운그레이드 체험기?

회사에서 테스트 폰으로 사용하는 갤럭시 S2가 ICS였는데…
다들 최소 OS를 2.2나 2.3으로 하기에 테스트 폰도 이 버전으로 낮추고 싶었습니다.

그래서 잠깐 짬을 내서 해 봤습니다.

준비물

[테그라크 블로그]에서 순정 펌웨어를 구했습니다.
[Odin 3.09]도 구해야겠죠?
현재 Windows에 삼성 디바이스 드라이버가 없다면 [XDA] 에서 구해야 할지도 몰라요.
다행히 Windows 8.1을 사용하는데 디바이스 드라이버가 들어있네요.

그럼 시작하겠습니다.

우선 전원을 꺼야겠죵?

볼륨 업 + 홈 버튼 + 전원 버튼을 같이 누릅니다. 계속…
그러면 Android system recovery 모드로 부팅이 됩니다.
볼륨 다운 버튼으로 이동해서 wipe data/factory reset 을 선택합니다. 그리고 전원 버튼을 누르면 선택이 되지요.
다수의 No와 하나의 Yes를 묻는데 볼륨키로 이동해서 전원 버튼으로 Yes를 선택합니다.

끝나고 나면 다시 복구모드로 돌아옵니다.
reboot system now를 선택함과 동시에
볼륨 다운 + 홈 버튼 + 전원 버튼을 같이 누르고 있습니다.
볼륨 다운입니다!!! 처음에는 볼륨 업, 지금은 다운!

펌웨어 다운로드하는 모드로 돌입됩니다.
볼륨 업을 눌려 계속 진행합니다.

다운로드 중… 이라고 뜹니다.
이제 PC와 연결하고 디바이스 드라이버 잡히고 나면
오딘(Odin)을 실행합니다. (ODIN은… 지금 핸드폰에 나온 화면 제일 위에 보면 ODIN MODE라고 나오는데 이것에서 따온 이름인가 봅니다.)

디바이스가 잡히면 ID:COM 항목에 하나 보입니다.
Auto Reboot, F. Reset Time 두개를 켜고
3.09에서는 AP라는 버튼을 눌려 받아둔 펌웨어를 선택합니다.
(BL: Bootloader, AP: 안드로이드 폰, CP: 셀룰러 폰???? 이 아닐까 싶은데 정확히는 모르겠네요.)

그리고 나면 펌웨어 파일을 분석을 하게 되고 이제 Start 버튼을 눌려서 펌웨어를 폰으로 전송합니다.

끝나고 나면 Auto Reboot 되겠죠? 그러면 … 순정 생강빵을 보실 수 있습니다.

[참고 자료: 러브드웹의 인터넷 이야기 – 갤럭시S2 진저브레드 다운그레이드 방법 & 아이스크림 샌드위치 업그레이드]

Android에서 사용하는 단위들 (px, sp, dp, in, mm, pt)

과거 PC가 컴퓨팅 환경의 중심이던 시절에는 대충 3가지 단위만 알면 되었는데요.
px, pt, in 정도였습니다.
Visual Studio로 다이얼로그를 만들다 보면 하나 더 필요하긴 했네요.
DLU

그런데 스마트폰으로 오면서 세상이 바뀌었습니다.

과거 PC 중심에서 아이콘은 대부분 32×32 크기가 보통이었죠.
그런데 최근 Full HD를 지원하는 스마트폰에서 32×32로 아이콘을 만든다면?
보는 것은 물론이고, 터치나 할 수 있겠습니까?

하지만 스마트폰이나 태블릿의 사양이 너무도 가지각색이라
저가형 태블릿에 맞춰 작업하면 최신 휴대폰에서 볼 수가 없고
최신 휴대폰에 맞춰 작업하면 저가형 태블릿에서는 화면을 다 가리고 말겁니다.

그래서 사람들은 다른 단위에 눈을 돌리기 시작했습니다.
실제 물리적인 디바이스에서 어떤 크기로 표현된다를 정할 수 있는 단위
그래서 대안으로 사용하자고 나온 단위들이 in, sp, dp, pt 등입니다.
이들 모두는 물리적인 크기 단위를 기반으로 하고 있다는 것.

앞으로 어플리케이션을 제작한다면 단위는 물리적인 크기를 기준으로 삼아야 할 것입니다.

본론!!!
단위를 정리해 보면 아래와 같습니다.

  • px
    픽셀. 화면에 표시되는 한 점!
    점이 차지하는 실제 크기는 디스플레이마다 다르다!
    PC 환경은 크게 차이가 나지 않지만 모바일 환경은 엄청 차이가 난다!!!
    여전히 컴퓨터 그래픽스에서 실제 연산하는 단위로 사용되고 있다. 어쩔 수 없다!
  • sp
    스케일링 된 픽셀
    픽셀에 대해 사용자의 표준 폰트 크기 설정의 비율을 곱해서 나온 값이다.
    표준 폰트를 디바이스에서 150% 크게 했다면 1 sp = 1.5 px 이 되는 것이다!
    (맞나? 안 맞나? BS가 이해한 것이 틀린가요?)
  • dp
    안드로이드의 현재 기준인 160 dpi의 디스플레이에서 1 px이 차지하는 크기이다.
    디스플레이가 320 dpi라면 1 dp = 2 px이 되는 것이다.
    현재 안드로이드 앱 개발에서 기본이되는 단위
  • in
    인치라고 부르는 단위. 약 25.4 mm (2.54 cm) 정도 되나?
  • mm
    미터 표기에서 나온 밀리 미터!
    이걸 모른다면 대한민국 의무 교육 기간을 허비하며 보낸 사람이다!!!
  • pt
    1/72 인치 정도의 물리적인 크기
    사실 원래의 의미는 다르다. 특정 단위를 잘게 나누어 1개를 포인트라는 용어를 써서
    정의한 사람들마다 실제 물리적인 크기가 달랐다.
    최근에는 DTP(탁상 출판 포인트, 포스트스크립트 포인트) 단위를 많이 쓰고 있는데 이것이 1/72 인치이다.
    Windows에서 보통 디스플레이의 dpi를 96 dpi로 보고 BS가 선호하는 9 pt 는 9 x 96 / 72 = 12 dots(px) 이 된다.
정리한 것을 보면 왜 안드로이드가 dp라는 단위를 표준으로 삼고 있는지 조금은 이해할 수 있을 겁니다.
물리적인 단위와 디스플레이의 단위 사이에서 적절히 사용할 수 있거든요.

Emulator Error: Could not load OpenGLES emulation library: Could not load DLL

에뮬레이터를 실행하는데 요따구 메시지가 뜹니다.

Emulator Error: Could not load OpenGLES emulation library: Could not load DLL

에뮬레이터는 Android Virtual Device Manager에서 Start 한 뒤에
Sysinternals Suite에 있는 Process Explorer를 가지고 해당 프로세스의 Command Line과 Working Directory를 확인해서
바로가기를 만들어 실행했습니다.
이러면 Console 창이 추가로 보이고 Log가 출력되는 것을 확인할 수 있는데요.
여기에서 위와 같은 메시지가 보이더라구요.

에뮬레이터의 실행파일 위치는 ATD 번들 패키지를 기준으로 하면
<ADT Path>/sdk/tools/emulator-arm.exe
입니다.

그리고 해당 DLL의 위치는
<ADT Path>/sdk/tools/lib
아래에
libEGL_translator.dll
libGLES_CM_translator.dll
libGLES_V2_translator.dll
libOpenglRender.dll
입니다. 당연히 못 찾을 거 같군요.

그래서 해당 파일을 복사해서 실행 파일과 동일한 위치로 넣었습니다.

잘 됩니다.

에뮬레이터에 한글 키보드 설치하기

ADT를 받아서 가상 머신을 생성하면 한글 입력을 못합니다.
삼성에서 안드로이드 핸드폰을 전세계에 그렇게 많이 팔아줬는데도 에뮬레이터에는 한글 키보드가 탑재 되지 않았습니다.

그래서 자신이 만든 앱에서 한글 입력이 필요한 경우에는 직접 구해서 설치해야 합니다.

현재 최신 버전인 0.82를 웹에서 구했습니다.
구글 플레이 또한 에뮬레이터에서 제공하지 않아 apk 파일을 직접 복사했습니다.

첨부된 파일을 받습니다.

아래와 같이 ADB를 통해 설치합니다.

adb install G:\Backup\GoogleKoreanIME_v0.82.apk

Google Korean IME v0.82: cfile5.uf.010FEA3451120B781F4D28.apk