2014년 9월 25일 목요일

Google Application Licensing (구글 앱 라이센싱 - LVL)

 이번에 유료앱을 하나 등록해 볼까 생각이 들어 구글 앱라이센싱을 적용해 보았다.
또 오래되면 잊어버릴지 모르니 일단 정리해 볼까 한다.

 물론 기본적으로 구글 개발자 페이지에 잘정리 되어있다. 그 내용을 바탕으로 요약 및 단축하여 작성하겠다.
- 구글 개발자 페이지 링크 : http://developer.android.com/google/play/licensing/index.html


1. LVL이란?

 우선 지금부터 사용할 라이브러리는 약어로 LVL(Licensing Verification Library)이다. 위의 페이지에 동작원리가 나와있다. 시간이 되면 한번 읽어보자. 안읽어봐도 적용하는데는 상관없지만 뭐 읽어두어 보자~~

 - LVL의 키 Interface
 총 두가지이다.







Policy
앱에 접속여부를 결정한다. 보통 서버혹은 캐쉬에저장된 데이터를 기반으로 결정하게된다. 커스텀으로 만들수도 있지만 기본적으로 구현된 객체를 사용하면된다.
LicenseCheckerCallback
어플리케이션의 접근을 관리한다. Policy 객체의 라이센스 응답에 의해 앱에서 취해주어야할 작업들을 연결해준다. 팝업을 띄운다던지, 구매페이지로 이동시킨다던지 하는 제어를 할 수 있다.


2. 사전 조건

 이 라이브러리가 나온지 아주 오래되어 사실 조건은 별다를게 없다.
 - API Level 3이상
 - 인터넷 억세스 가능(라이센스 서버와 통신하므로)


3. 환경설정

 - 에뮬레이터나 실기기 모두 가능하다고 나온다.
 - 일단 나는 실기기에서 바로 테스트 했다. 에뮬레이터에서 테스트 하려면 조금더 복잡한 과정이 필요하니 이부분은 필요하면 위의 개발자페이지를 참고하자.

 - LVL의 다운로드
 - 구글이 업데이트를 잘안한다. SDK Manager를 띄워서 아래의 항목을 확인한다.


 - Google Play Licensing Library 라고 보이는것이 설치되어있는지 확인하자.
 - 안되어있다면 설치
 - 받았다면, <sdk>/market_licensing/library/ 내부에 존재하는 라이브러리 소스를 import 해오든지 하여 library project로 이클립스 등에 가져온다.
 - 가져왔다면 내가 적용시키기 원하는 프로젝트의 프로퍼티에서 해당 라이브러리를 포함시켜준다.
 - 뭔말인고 하니 아래화면에서 추가해주면 된다는 이야기다.

 - 필자는 google-license라는 이름으로 가져와서 포함시켰다.
 - 이제 환경 설정은 끝났다.



4. 실제 적용

 - 실제적용은 위에서 받은 Library 패키지 안의 샘플을 보면 쉽게 적용이 가능하다.
 - 사실 샘플 그대로 써도 대부분 무방하다고 보면된다.

 - Manifest 파일.
<!-- Required permission to check licensing. -->
    <uses-permission android:name="com.android.vending.CHECK_LICENSE" />
 위의 권한을 추가해준다.

 - MainActivity
  가장 front의 액티비티만 고쳐주면된다. 즉 Manifest와 MainActivity 두 개만 수정하면됨

   > 멤버변수 선언부
      - 공개 키를 넣어주고, SALT에 임의의 숫자들을 넣어준다.
private static final String BASE64_PUBLIC_KEY = "디벨롭퍼 콘솔에서 생성된값을 여기에";
// Generate your own 20 random bytes, and put them here.
private static final byte[] SALT = new byte[] { -46, 11, 11, -128, -11,
-57, 74, -64, 51, 88, -95, -45, 77, -22, -36, -11, -11, 11, -11,89 };
private LicenseCheckerCallback mLicenseCheckerCallback;
private LicenseChecker mChecker;
private Handler mHandler;

   > onCreate 함수 내부.

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.activity_main);
mHandler = new Handler();
// Try to use more data here. ANDROID_ID is a single point of attack.
String deviceId = Secure.getString(getContentResolver(),Secure.ANDROID_ID);
// Library calls this when it's done.
mLicenseCheckerCallback = new MyLicenseCheckerCallback();
// Construct the LicenseChecker with a policy.
mChecker = new LicenseChecker(this, new ServerManagedPolicy(this,
new AESObfuscator(SALT, getPackageName(), deviceId)),BASE64_PUBLIC_KEY);
doCheck();
...
     > Inner Class 추가. Callback함수이다. 액티비티가 직접 implement 해도 된다.

private class MyLicenseCheckerCallback implements LicenseCheckerCallback {
public void allow(int policyReason) {
if (isFinishing()) {
// Don't update UI if Activity is finishing.
return;
}
// Should allow user access.
displayResult(getString(R.string.allow));
}
public void dontAllow(int policyReason) {
if (isFinishing()) {
// Don't update UI if Activity is finishing.
return;
}
displayResult(getString(R.string.dont_allow));
displayDialog(policyReason == Policy.RETRY);
}
public void applicationError(int errorCode) {
if (isFinishing()) {
// Don't update UI if Activity is finishing.
return;
}
String result = String.format(
getString(R.string.application_error), errorCode);
displayResult(result);
}
}

     > Dialog Method들 추가. - 이부분은 dialog가 fragment로 구현되는 요즘 버전이 아닌 옛날 버전으로 되어있다. 구글에서 샘플업데이트를 안했다. 그래서 deprecated된 함수를 그대로 쓰고 있다. 각자 고쳐서 팝업 처리하도록 하자.
protected Dialog onCreateDialog(int id) {
final boolean bRetry = id == 1;
return new AlertDialog.Builder(this)
.setTitle(R.string.unlicensed_dialog_title)
.setMessage(
bRetry ? R.string.unlicensed_dialog_retry_body
: R.string.unlicensed_dialog_body)
.setPositiveButton(
bRetry ? R.string.retry_button : R.string.buy_button,
new DialogInterface.OnClickListener() {
boolean mRetry = bRetry;
public void onClick(DialogInterface dialog, int which) {
if (mRetry) {
doCheck();
} else {
Intent marketIntent = new Intent(
Intent.ACTION_VIEW,
Uri.parse("http://market.android.com/details?id="
+ getPackageName()));
startActivity(marketIntent);
} }
})
.setNegativeButton(R.string.quit_button,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int which) {
finish();
}
}).create();
}
private void doCheck() {
// mCheckLicenseButton.setEnabled(false);
setProgressBarIndeterminateVisibility(true);
// mStatusText.setText(R.string.checking_license);
mChecker.checkAccess(mLicenseCheckerCallback);
}
private void displayResult(final String result) {
mHandler.post(new Runnable() {
public void run() {
// mStatusText.setText(result);
setProgressBarIndeterminateVisibility(false);
// mCheckLicenseButton.setEnabled(true);
}
});
}
private void displayDialog(final boolean showRetry) {
mHandler.post(new Runnable() {
public void run() {
setProgressBarIndeterminateVisibility(false);
showDialog(showRetry ? 1 : 0);
// mCheckLicenseButton.setEnabled(true);
}
});
}

    > 마지막으로 onDestroy를 Override하여 아래 코드 추가.

@Override
protected void onDestroy() {
super.onDestroy();
// License 적용시
mChecker.onDestroy();
}

5. 완료

  - 이로써 모든 적용이 끝났다. 사실 두개의 파일만 고치면 간단히 적용할 수 있다.
  - 테스트는 일단 알파 혹은 베타 버전으로 apk를 업로드하고 이것을 다운받아서 실행해본다.
  - 개발자 콘솔의 좌측 설정에서 계정세부정보 아래쪽을 보면 라이선스 테스트를 할 수 있다.
  - Not_licensed, Licensed등으로 바꾸면서 테스트 해본다.



2014년 9월 22일 월요일

Hade's 4th App



바로가기 - 구글 플레이 스토어

 사실 처음 앱을 만들 땐 그래도 어느정도 수익이나는걸로 생각했다. 그러나 그건 나의 큰 오산이었다. 이미 이 생태계도 포화상태이며 레드오션이다. 수익을 노리긴보다는 자기만족으로 하는편이 마음편하다는 것을 느꼈다. 그래서 난 꾸준히 앱을 한 100개까지 만들어볼 생각이다.

 각설하고 네번째 앱은 다시 게임이다. 게임을 만들때가 사실 제일 재밌다. 그러나 이번게임도 너무 현학적이랄까? 떨어지는 숫자를 소인수분해하는 게임인데 교육용으로 쓰면좋지않을까 생각이든다.

 이게임은 surfaceview를 처음으로 사용하고 사운드와 배경음악도 처음으로 넣어본 앱이다.public domain의 이런 소스들을 찾는것도 시간이 오래걸렸다. BGM은 몰라도 사운드는 나중에 내가 직접 녹음해버릴까 생각도 들었다.

 surfaceview의 제어가 좀 까다로왔고 멀티터치를 구현하고나서 제일 뿌듯했던것 같다. 다음번엔 이런 어려운 게임을 지양해야되지 않을까 생각을 남긴 앱이다.

바로가기 - 구글 플레이 스토어 

2014년 9월 16일 화요일

Hade's 3rd App


LocaPhoto


 2번째앱을 만드느라 기력을 많이 소진해서 간단한앱을 만들고싶었다. 내 의도데로 이 앱은 매우긴단한앱이다.

 사진에 지도를 붙이는 단순한앱이다. 개인적으로는 사진과 구글맵 그리고 비트맵을 제어하는 연습을 한 앱이다.

 그러나 일부 저사양 스마트폰에서 메모리에러가 발생했다. 비트맵을 다룰땐 메모리를 주의해야한다는 점을 배울 수 있었다.

 처음에는 아무도 쓰지않다가 최근(2014.9) 들어 다운로드와 사용자가 꽤? 아주조금 늘었다. 사용자가 증가한 기념으로 최근에 업데이트를 했다. 사진위치를 자유롭게 조정할 수있게 변경했다.

 개인적으로는 이 앱의 이름이 마음에든다. location 과 photo의 합성어로 로카포토~ 로까뽀또 뭔가 남미느낌이라 좋다.


2014년 9월 14일 일요일

Hade's 2nd App


Colors
 처음 안드로이드를 개발하려고 마음먹은게 2048이란 게임을 보고난 후 였다. 별다른 화려한 디자인이나 기술없이도 아이디어만으로도 훌륭한 게임을 만들 수 있다는 가능성을 보았기 때문이다.

 이 게임은 사실 2048을 모티브로 하고 있다. 그러나 벌떼처럼 생겨난 2048의 아류작이 되긴 싫었다. 기본적인 동작은 비슷하되 점수에 대한 메카니즘은 전혀 달랐다. 색의 삼원색에 기반하여 2의 제곱기반의 퍼즐과는 차별성을 두었다.

 그러나 이 부분이 유져에겐 어렵게 느껴졌나보다.. 지인들중엔 어렵다고 하는 경우가 많았다. 2048이 1차원적인반면 이 게임은 약 1.5-2차원정도였기 때문이라고 생각한다. 

 이런 류의 퍼즐은 surfaceview를 쓸 필요도 없다. 실시간으로 화면이 변하는 것도 아니고 턴방식이기 때문이다. 하지만 내부적으로 처리할 알고리즘은 꽤나 까다로운 면이 많았다. 숫자로 하는 경우 보다 경우의 수가 훨씬 많고 복잡하기 때문이다. 사실 2048같은 숫자기반의 게임은 이 게임에 비해 만들기가 매우 쉽다. 숫자 기반의 처리는 컴퓨터와 친숙하고 매우 논리적이고 간단하게 처리할 수 있기 때문이다.

 이 게임을 만들면서 사실 잃어버렸던 프로그래밍의 즐거움을 찾을 수 있었다. 내가 어린시절 프로그래밍을 좋아했던 것은 이런 점 때문이었다는 것을 다시 느끼게 되었다.
 - 하나하나 해결해 나가는 재미
 - 내 생각데로 동작하는 프로그램
 - 어려움이나 막힌 부분을 해결하였을 때의 희열

 이 앱에서 가장 힘들었던 부분은 구글 플레이 서비스 연동 부분이었다. 리더보드를 연동하는 부분이었는데 레퍼런스만 보고하기엔 좀 까다로웠다. 사실 모든 것들이 그러하듯 알고나면 정말 아무것도 아닌것들이지만 말이다.

 또한 이 앱을 만들면서 디자인의 필요성을 새삼 느꼈다. 색깔하나를 고를 때도 이뻐보이는 색을 고르는 감이 있어야 한다. 나는 이런 쪽으로는 잼병이라 매우 힘들었다. 모든 그래픽작업 또한 나혼자 하고 있는데, 코딩에 3이들어가면 그래픽 및 기타 작업에 7이 들어간다.

 개인적으로는 내가 만든 것들을 디자이너 파트너를 구하게 되면 새로 리뉴얼해서 모두 싹 갈아 엎고 싶다. 예전 게임회사를 다닐 때 디자이너 친구들을 많이 사귀어둘걸 하는 후회가 든다.

 첨으로 개발한 안드로이드 게임이자 완성후 만족감도 가장 높았던 앱이라 애착이 많이 간다.

플레이스토어 링크

카지노 소개 #2 모나코

 모나코라면 어디에 붙어있는지 모르는 사람도많을것이다. 도시국가이며 왕국인 국가, 모나코 F1 그랑프리 또는 박주영이 있었던 AS모나코 정도가 알려져있다. 좀 옛날 사람이라면 그레이스 켈리 왕비의 나라로 알고 있을지도 모른다.

모나코는 그러나 유구한역사를 가진 카지노를 가지고있다. 그 이름부터 멋진 몬테카를로 카지노이다.

 궁전같은 외관에 마카오나 라스베가스의 여느 카지노 호텔과는 격부터 달라보이는 그런 느낌. 마카오나 라스베가스에 우후죽순처럼생겨난 그런카지노가 아닌 클래식한 카지노가 이 곳이다.
 사실 유럽엔 이런느낌의 카지노가 많은데 그 중 이 몬테카를로가 가장 클래식하지 않을까 생각해본다.


 카지노입구엔 슈퍼카들이 나란히 주차되어있다. 또한 이 카지노는 특이하게 견학이 가능하다. 견학하는 구역이 따로있고 입장료가 있던것으로 기억한다. 아마 이 카지노의 역사를 보는 박물관느낌의 어떤 것이 아닐까? 그러나 난  겜블을 하러왔지 견학을 온건아니다.

 이제 본론으로 들어가서 모나코에 테이블 게임을 갖춘 카지노는 이곳이 유일하다. 몇개의 카지노가 더 있지만 모두 슬롯머신만 갖추고 있다.(2013기준)
 테이블게임의 미니멈은 15-20유로 정도로기억한다. 유구한 역사와달리 테이블은 많지 않으며 10여개 정도가 전부였던 것 같다.
 이런 카지노에서는 겜블에 열올리지말고 중 근세 유럽의 카지노 느낌을 만끽하고 즐기다 오는 건 어떨까하는 생각이 든다.

2014년 9월 13일 토요일

Toast - 메시지의 표시 위치 설정

일반적으로 Android에서 간단한 메시지를 쓰기위해



Toast.makeText(getApplicationContext(), getResources().getString(R.string.toast_move_available) , Toast.LENGTH_LONG).show();



위와 같이 한줄로 처리하곤 한다.

이경우 기본적으로 중앙 하단에 메시지가 표시되는데,

아래처럼 toast객체를 만들어 위치를 설정할 수 있다.


Toast toast = Toast.makeText(this,
getResources().getString(R.string.text_toast_cannot_undo),
Toast.LENGTH_SHORT);

toast.setGravity(Gravity.CENTER, 0, 0);


toast.show();



2014년 9월 10일 수요일

카지노 소개 #1 마닐라

2014년 8월 기준

마닐라에는 크게 관광할 거리가 없다.
그러나 마카오와 비교할 때, 마카오 정도의 관광할 거리는 있는 것 같다.

곳곳에 크고 작은 카지노가 많이 들어서 있지만 주로 아래 세 곳이 제일 유명한 
카지노라 할 수 있다.

* 공통사항 : 블랙잭의 경우 내가 본 마닐라 카지노는 모두 CSM(Continuous Shuffle Machine)을 사용하고 있었다. 따라서 카드카운팅은 안됨~.


1.RWM(Resort World Manila)



공항과 가장 가까이에 있으며, 보통 밤비행기가 많은 마닐라의 경우 첫날밤은 이곳에 머무를 확률이 크다.
여기엔 세개의 호텔이 모여있는데, 마닐라 메리어트, 막심, 레밍턴 이 세개가 바로 그것이다. 하지만 메리어트,막심과 레밍턴의 차이는 하늘과 땅차이라서 대부분은 레밍턴 호텔에 묵을거라 예상된다.

레밍턴 호텔은 1박에 6~8만원 내외로 매우 저렴하다고 볼 수 있다. 또한 RWM에서 콤프를 조금만 모아도 보너스 1박이 가능하다. 그러나 호텔 객실자체는 너무 습하여 당장이라도 개구리가 뛰쳐나올것 같은 느낌으로 오래 머무는 것은 권하지 않는다. 도착 첫날 갈곳이 없을때 머무는 것을 권한다.

또한 RWM의 환전율은 매우 좋은 편이라, 다른 카지노 호텔 보다 이곳에서 환전하기를 권한다.

RWM카지노 내부의 부페형태의 작은 식당이 있는데 이곳의 갈릭라이스가 마닐라에서 먹어본 음식중 가장 맛있었다.

RWM의 객장은 Table Game Minimum 300페소 부터 시작한다. 조금 높은 테이블은 500페소이다.

 필자는 카지노에서 블랙잭을 주로 하는 편인데 마닐라에도 변형 블랙잭 테이블이 몇 개 있다. 그 중에서 RWM에 있던 좀 인상깊었던 블랙잭은 Free Double/Split Bet 테이블이었는데, Double이나 Split을 Free bet으로 할 수 있다. 물론 이겼을 때는 Free bet이지만 초기 배팅금액 만큼 다 지급해주고, 지더라도 초기 금액만 잃으니 매우 좋아 보인다.

 하지만 카지노가 땅파서 장사하지는 않는 법, 이 테이블에서는 딜러가 22면 무조건 Push이다. 그러나 더블과 스플릿을 적극 활용하면 충분히 유리한 조건으로 게임할 수 있을것이라 생각한다. 단 블랙잭의 Basic Strategy로 승부하면 안된다. 이 테이블에서는 Double은 무조건 하는것이 좋고, Split도 10,10만 아니면 가능한 최대한 활용하는것이 플레이어에게 유리하다.


2.Solaire Casino


 Solaire 지도

마닐라 베이 근처에 자리잡고 있으며 주변으로는 대형 쇼핑몰 SM Mall이 있다. 카지노 입구에 두명의 필리핀 여성이 있는데, 키가 매우크고 늘씬하다. 아마 이 호텔의 상징이 아닐까 생각드는데, 아무것도 하지 않는다.

이 카지노는 위치가 가장 좋은 편이고 주변에 쇼핑몰과 수산시장도 있어서 접근이 편리하다. 마찬가지로 거의 마카오의 중형 호텔급 규모를 자랑한다.

마닐라의 공통 미니멈이 300,500이다. 사실 300페소라고 해도 7500원 500페소면 12500원이니 마카오와 비교하면 매우 싸다고 할 수 있다.

마카오의 주말 미니멈이 300홍콩달러(약 45,000원)임을 감안하면 마음 편하게 즐기다가 올 수 있다.

3.Hyatt Regency Hotel Casino


 Hyatt Manilla

Solaire에서 북쪽으로 조금 올라오면 있다. 이 곳이 한국의 많은 도박 연예인들의 종착지가 된 카지노이다.

 시설은 앞서 소개한 두 곳 보다 아주 약간, 낙후되긴하였지만 큰 차이는 없다. 앞서 소개한 두 곳과 미니멈 맥시멈 동일하다.

4.기타 카지노


- Sofitel Casino

 소피텔 호텔에 딸려있다. 매우 영세한 규모의 카지노이며, 테이블 게임만 있다.
 블랙잭 테이블은 오직 1개이며 저녁 6시부터 오픈한다.
 이 카지노는 테이블에서 칩을 바꾸는게 아닌 환전소에서 칩을 바꿔와서 게임을 해야 한다.
블랙잭이라는것이 아시아에선 인기가 별로 없기에, 이야기를 해야 테이블을 열어준다.

 딜러들도 아주 대충 일을 해서 새벽에 가면 졸면서 일을 하는 경우도 목격했다.
 위의 세곳과는 아주 차원이 다른 대형 마트 VS 동네 슈퍼 정도의 규모이며, 다양하고 화려한 느낌의 카지노를 원한다면 위의 세곳 이외에는 없다고 보면 된다.

 또한 영세 카지노는 환전율이 매우 불리하므로 이런곳에서는 너무 열을 내서 플레이를 하지말도록 하자.






Hade's 1st App

JustCheck - Simple CheckList
Cover art

안드로이드를 공부하면서 만든 앱.

심플함을 지향한 체크리스트 앱이며 본인이 사용하기 위해 만든 앱.


체크리스트 앱이야 수 없이 많기 때문에 이 앱으로 뭔가 경쟁을 하겠다는 마음으로
만든것이 아니고 본인이 사용하기 편한 기능, 나에게 꼭 필요한 기능만 넣는다는
생각으로 만든 앱