2013-08-20 2 views
37

재고 Android-Developer 라이센싱 라이브러리 instructions을 보았습니다.하지만 개요에서 프로세스의 몇 가지 주요 단계가 생략되어 작동하는 방법을 완전히 설명하지 못했습니다.Android 앱용 Google Play 라이선스를 구현하려면 어떻게해야하나요?

누군가 Android 앱에서 라이센스 라이브러리를 설정하기 위해 작동하는 명시적인 작업 집합을 제공하여 사용을 허용하기 전에 사용자가 Google Play에서 앱 비용을 지불했는지 확인할 수 있습니까?

+1

실제로 질문을 올리십시오 (예 : 'Android 라이선스에 대한 유용한 자습서가 있습니까?'). 자습서를 답변으로 추가 하시겠습니까? – ozbek

+0

@shoerat 나는 그것에 대해 생각했다. 나는 내 자신의 질문에 대답 할 수 있었다고 생각하지만, 누군가가 그것을 읽었을 때 그것은 다소 clunky 한 것처럼 보일 것이다. –

+0

흠 ... 동의하지 않으려 고 서 있습니다. 자, 여기에 서있는 방식으로 다른 사람이 입력 할 방법이 없습니다. 1) 여기에서 자체 질문에 대답해도 괜찮습니다. 2) "오프 사이트 링크 없음"을 추가 할 수 있습니다. 3) 정말로 관심이 있으시면 답변을 ** 커뮤니티 위키 **로 할 수 있습니다. 그래서 그것은 명성 점수에 대한 외침처럼 보이지 않을 것입니다. – ozbek

답변

134

저는 얼마 전에 내 응용 프로그램에서 라이센스를 구현하고 마침내 작동하도록했습니다. 시작하기에 도움이되는 몇 가지 사항과 모든 사람과 함께 발견 한 몇 가지 문제 및 솔루션을 나누고 싶었습니다. 아래에 링크 된 android dev 튜토리얼은 괜찮 았지만 그다지 유용하지 않으므로 튜토리얼을 작성하기로했습니다. 즐기십시오, 그리고 그것이 당신을 돕기를 바랍니다!

개발자 페이지로 연결 here.

1. 당신이 필요합니다

것들 시작하기.

1.1 키 귀하의 Base64로 고유 한 응용

어떻게 그것을 얻을 수 있습니다 :

을 수행합니다. 개발자 콘솔로 이동하십시오. Link.

b. 앱용 애플리케이션 초안을 아직 만들지 않았다면 지금 시작하십시오.

c. 초안을 만든 후에는 .apk을 알파 또는 베타로 업로드하는 것이 좋습니다. 게시되지 않은 상태로 둡니다.

d. 클릭 Services & APIs

e. 아래로 스크롤하여 찾을 수 YOUR LICENSE KEY FOR THIS APPLICATION

f. 다음과 같이 키를 앱에 복사하십시오.

private static final String BASE64_PUBLIC_KEY = "YOUR LICENSE KEY FOR THIS APPLICATION"; 

공백이 없는지 확인하십시오.

1.2 소금

가. 소금은 무엇입니까?

salt은 암호를 해싱 할 때 추가 입력되는 임의의 데이터입니다. 그들은 dictionary attacksrainbow table 공격을 방어하는데 사용됩니다.

b. 어떻게 구할 수 있습니까?

This은 임의의 소금을 생성하는 좋은 링크입니다. 정확히 개의 임의의 정수가 있어야하므로 생성 할 임의의 문자열 양에 대해 20을 입력하고 각 문자열은 2 자 여야합니다 (이 예에서는 사용하지 않아도됩니다). 숫자를 확인하고 동일한 문자열이 허용되는지 확인하십시오. 음수 일 수도 있습니다. 중복성을 제거하려고 시도합니다 (예 : 00 -> 0, 일관성을 위해.

c. 소금은 어디에 두어야합니까?

변수를 선언 할 때 임의의 소금을 제외하고이 코드를 넣으면됩니다.

private static final byte[] SALT = new byte[] {YOUR RANDOM SALT, COMMA SEPARATED, 20 INTEGERS}; 

2. 이클립스에 LVL (라이센스) 라이브러리와 코드를 가져 오기

당신은 라이브러리

가져 오기

2.1이 필요합니다. Open Android SDK Manager

b. Extras

c로 이동하십시오. 설치 Google Play Licensing Library

d. SDK 관리자 맨 위에 나열된 SDK 설치 경로를 찾으십시오.

e. 여기에 있으면 <sdk>/extras/google/play_licensing

f로 이동하십시오. 이클립스에서 file을 클릭 한 다음 import을 클릭 한 다음 Existing Android Code Into Workspace을 클릭하고 파일 경로를 묻는 메시지가 표시되면 play_licensing 폴더로 이동하여 library을 클릭합니다.

g. library 프로젝트를 가져온 다음 마우스 오른쪽 버튼을 클릭하고 properties을 클릭하십시오. 왼쪽에있는 Android을 클릭하고 하단으로 이동하여 Is Library을 체크 한 다음 적용을 누릅니다. 이것은 Eclipse가이 프로젝트 코드를 라이브러리로 사용할 수 있다는 것을 알게합니다.

h. 라이선스를 추가 할 앱을 마우스 오른쪽 버튼으로 클릭하고 속성을 클릭 한 다음 Android을 클릭합니다. 하단으로 가서 library을 클릭하고 빌드 경로에 추가하십시오. 라이브러리를 Android Dependencies 폴더로 가져와야합니다.

i. 프로젝트가 다음 단계로 진행되도록 설정되었습니다.

2.2 변수 SALT

private Handler mHandler; private LicenseChecker mChecker; private LicenseCheckerCallback mLicenseCheckerCallback; boolean licensed; boolean checkingLicense; boolean didCheck; 

2.3 코드를

앱 하단에이 코드를 붙여

KEY 당신과 함께 선언합니다. 이 구현은 라이센스가 유효하지 않은 경우 사용자에게 알리고 앱을 구매하거나 종료하도록 프롬프트합니다.

private void doCheck() { 

     didCheck = false; 
     checkingLicense = true; 
     setProgressBarIndeterminateVisibility(true); 

     mChecker.checkAccess(mLicenseCheckerCallback); 
    } 


    private class MyLicenseCheckerCallback implements LicenseCheckerCallback { 

     @Override 
     public void allow(int reason) { 
      // TODO Auto-generated method stub 
      if (isFinishing()) { 
       // Don't update UI if Activity is finishing. 
       return; 
      }    
      Log.i("License","Accepted!");  

       //You can do other things here, like saving the licensed status to a 
       //SharedPreference so the app only has to check the license once. 

      licensed = true; 
      checkingLicense = false; 
      didCheck = true; 

     } 

     @SuppressWarnings("deprecation") 
     @Override 
     public void dontAllow(int reason) { 
      // TODO Auto-generated method stub 
      if (isFinishing()) { 
        // Don't update UI if Activity is finishing. 
        return; 
       } 
       Log.i("License","Denied!"); 
       Log.i("License","Reason for denial: "+reason);                    

         //You can do other things here, like saving the licensed status to a 
         //SharedPreference so the app only has to check the license once. 

       licensed = false; 
       checkingLicense = false; 
       didCheck = true;    

       showDialog(0); 

     } 

     @SuppressWarnings("deprecation") 
     @Override 
     public void applicationError(int reason) { 
      // TODO Auto-generated method stub 
      Log.i("License", "Error: " + reason); 
      if (isFinishing()) { 
       // Don't update UI if Activity is finishing. 
       return; 
      } 
      licensed = true; 
      checkingLicense = false; 
      didCheck = false; 

      showDialog(0); 
     } 


    } 

    protected Dialog onCreateDialog(int id) { 
     // We have only one dialog. 
     return new AlertDialog.Builder(this) 
       .setTitle("UNLICENSED APPLICATION DIALOG TITLE") 
       .setMessage("This application is not licensed, please buy it from the play store.") 
       .setPositiveButton("Buy", new DialogInterface.OnClickListener() { 
        public void onClick(DialogInterface dialog, int which) { 
         Intent marketIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(
           "http://market.android.com/details?id=" + getPackageName())); 
         startActivity(marketIntent); 
         finish(); 
        } 
       }) 
       .setNegativeButton("Exit", new DialogInterface.OnClickListener() { 
        public void onClick(DialogInterface dialog, int which) { 
         finish(); 
        } 
       }) 
       .setNeutralButton("Re-Check", new DialogInterface.OnClickListener() { 
        public void onClick(DialogInterface dialog, int which) { 
         doCheck(); 
        } 
       }) 

       .setCancelable(false) 
       .setOnKeyListener(new DialogInterface.OnKeyListener(){ 
        public boolean onKey(DialogInterface dialogInterface, int i, KeyEvent keyEvent) { 
         Log.i("License", "Key Listener"); 
         finish(); 
         return true; 
        } 
       }) 
       .create(); 

    } 

2.4 장치 ID는

는 시뮬레이션 직렬 또는 TelephonyManager.getDeviceId(); 사용 여부에 대해 과거에 이것에 대해 약간의 논쟁이 있었다하기하지만, 일반적으로는 다음 코드를 사용하는 것이 좋습니다 최대한의 호환성을 위해 기기의 ANDROID_ID을 가져 오십시오.라이센스 검사기

(A)의

String deviceId = Secure.getString(getContentResolver(), Secure.ANDROID_ID); 
Log.i("Device Id", deviceId); //AN EXAMPLE OF LOGGING THAT YOU SHOULD BE DOING :) 

2.5 제작. doCheck();에 전화하기 전에 모든 것이 제대로 만들어 지도록이 코드를 앱에 넣어야합니다. 내가 LVL의 내 구현을하고 때

mHandler = new Handler(); 
mLicenseCheckerCallback = new MyLicenseCheckerCallback(); 
mChecker = new LicenseChecker(this, new ServerManagedPolicy(this, new AESObfuscator(SALT, getPackageName(), deviceId)), BASE64_PUBLIC_KEY); 

, 당신이 라이센스에 문제가있는 경우, 당신은 mChecker = new LicenseChecker(this...getApplicationContext()에의 첫 번째 this을 변경할 수 읽기, 광산없이 작동하는 듯하지만, 만약을 .

2.6 추가 권한

. 응용 프로그램에 추가해야하는 두 가지 권한이 있습니다. manifest 파일.

<uses-permission android:name="android.permission.INTERNET"/> 
<uses-permission android:name="com.android.vending.CHECK_LICENSE"/>   

2.7 당신이 적절한 수입을 가지고 있는지 확인하십시오!

당신은 이미 이것을했을 것입니다.하지만 당신이 점검 할 좋은 곳이라고 생각했습니다.

2.8 라이센스를 호출하는 방법을

를 확인합니다. 라이센스를 확인할 때마다 doCheck(); 번으로 전화하십시오. 예를 들어 앱이 처음 실행되면 확인을 수행합니다.

3. 라이센스를 게시하기 전에 라이센스가 작동하는지 테스트하려면 어떻게합니까?

3.1 테스트 장치

구성. 나는 개인용 전화도 가지고 있는데 테스트 용으로 사용한다. 휴대 전화에 등록 된 Google 계정은 단 하나 뿐인 것이 좋으며 역사적으로 볼 때 조금 더 편합니다. Settings -> Accounts으로 가면 계정을 확인할 수 있습니다.

3.2 개발자 콘솔을

구성. 개발자 콘솔을 열고 왼쪽의 Settings으로 이동합니다.

b. 찾기 License Testing

c. 귀하의 이메일 주소가 Gmail accounts with testing access

d에 나열되어 있는지 확인하십시오. 이제는 테스트 목적에 맞게 테스트 응답을 변경할 수 있습니다. 앱이 그에 따라 응답해야합니다. SharedPrefs를 통해 데이터를 저장하는 경우 테스트 할 때마다 앱 데이터를 지워야 함을 기억하십시오. 테스트 응답을 변경 한 후에 저장을 클릭하면 아무 일도 일어나지 않습니다! 나는 이것에 대해 여러 번 잊어 버렸고 편두통으로 끝났습니다. 그런 다음 악취가 나는 저장 버튼을 보았습니다. Lol.

4.상황이

을 확인

4.1 조건부 면허를 시도합니다. didCheck 데이터를 SharedPreferences에 저장하면이 코드를 시도 할 수 있습니다.

if(didCheck==false){ 
     Toast.makeText(this, "Checking application license...",  Toast.LENGTH_SHORT).show(); 
     doCheck(); 
     Log.i("Checking!", "Checking license!"); 
    } 

4.2 SecurePreferences

를 사용하여 SharedPreferences 암호화. 이 link으로 이동하십시오.

b. SecurePreferences.java의 코드를 복사하여 프로젝트에 정확히 동일한 이름의 클래스에 붙여 넣으십시오.

c. 이 구현에 대한 정보는 ReadMe.md을 참조하십시오.

5. 문제 해결

라이센스 두통의 한 지옥이 잘못 될 수있는 많은 일들이 있습니다 간단하기 때문에, 문제 해결을 할 수 있습니다. 예를 들어, 네트워크 문제 또는 서버 문제로 인해 머리카락을 찢을 수 있습니다. 적절한 로깅을 사용하면 문제를 해결할 수 있고 서버 또는 응용 프로그램에서 추적 할 수있는 경우 서버 응답 코드를 얻을 수 있습니다. 나는 여러 번이 일을해야만했다.

5.1 나는 서버에서

가능한 수정을 아무것도 반환 내 응용 프로그램을 얻을 수 없습니다

을 수행합니다. 앱에 올바른 KEY이 있는지 확인하십시오.

b. 진행의 각 단계를 로깅하고 있는지 확인하십시오.

c. 로그에서 라이센스 서비스를 확인하십시오. 그것은 무언가가 잘못되었다는 것을 알아 내는데 유용 할 수 있습니다.

d. allow()dontAllow()applicationError()에는 @Override 개의 태그가 있어야합니다.

5.2 내 응용 프로그램은 항상 내가 테스트 응답

A의로 설정 상관없이 LICENSED 또는 NOT_LICENSED 말한다. 내가 가지고있는 최선의 치료법은 기다리는 것이다. 짧은 시간 내에 많은 테스트를 수행하면 항상 재 시도 코드 인 서버 코드 291이 전송됩니다. 나는 밤새 기다렸고 모든 것이 다음날 아침에 잘 돌아갔다.

b. Google Play 앱과 Google Play 서비스 앱의 데이터 (캐시가 아닌)를 삭제할 수 있습니다. 그런 다음 재생을 열어 모든 라이센스를 수락하고 다시 시도하십시오.

c. 앱 데이터를 지 웁니다.

5.3 디버깅을위한 서버 응답 코드 목록

로그 할 경우이 십진수 값은 int reason으로 설정해야합니다. 이 테이블을 사용하여 서버가 실제로 앱에 보내는 내용을 참조하십시오.

LICENSED = Hex: 0x0100, Decimal: 256 
NOT_LICENSED = Hex: 0x0231, Decimal: 561 
RETRY = Hex: 0x0123, Decimal: 291 
LICENSED_OLD_KEY = Hex: 0x2, Decimal: 2 
ERROR_NOT_MARKET_MANAGED = Hex: 0x3, Decimal: 3 
ERROR_SERVER_FAILURE = Hex: 0x4, Decimal: 4 
ERROR_OVER_QUOTA = Hex: 0x5, Decimal: 5 
ERROR_CONTACTING_SERVER = Hex: 0x101, Decimal: 257 
ERROR_INVALID_PACKAGE_NAME = Hex: 0x102, Decimal: 258 
ERROR_NON_MATCHING_UID = Hex: 0x103, Decimal: 259 

5.4 더 많은 공간을! 그들은 올 것이다!

여러분 모두에게 도움이되기를 바랍니다. 내가 할 수있는대로 최선을 다해 두목과 수정 사항을 공유하려고했는데 이것이 도움이되기를 바랍니다!

오류가 발생하면 최대한 빨리 해결할 수 있도록 알려주세요.

+11

위대한 업적과 헌신 ... 고맙습니다. 좋은 일을 계속 지켜라. –

+0

매우 유용합니다 - 질문을 작성하기 위해 편집했는데 다시 열릴 수 있습니다. 노력에 감사드립니다. – SQLiteNoob

+2

위대한 설명, 한 가지 중요한 사실이지만, ''은 필요하지 않습니다. 라이센스를 확인하기 위해 앱이 직접 인터넷을 필요로하지 않는다고 말하는 것이 중요합니다. – SagiLow

관련 문제