JGooglePlay icon indicating copy to clipboard operation
JGooglePlay copied to clipboard

How-to docs

Open gergelyke opened this issue 11 years ago • 3 comments

Could you add some hint/tips on how to use this project?

gergelyke avatar Jun 12 '14 06:06 gergelyke

Just a short example here, I think you can find out the rest by trying :)

AndroidContext android = Android.Context.randomGalaxyNexus().setEmail("YOUR_EMAIL").setAndroidId("ANDROID_ID");
String authToken = new AndroidAuth().getAuthTokenResponse(android, "YOUR_PASSWORD", "androidmarket", "com.android.vending", "10321bd893f69af97f7573aafe9de1dc0901f3a1" /* Google's sig hash */,  false, AuthType.Password).getData(DataField.AUTH_TOKEN);
RequestContext req = new RequestContext();
info.put(RequestContext.KEY_ANDROID_ID_HEX, android.getAndroidIdHex());
info.put(RequestContext.KEY_AUTHORIZATION_TOKEN, authToken);
info.put(RequestContext.KEY_CELL_OPERATOR_NUMERIC, android.getCellOperator());
info.put(RequestContext.KEY_CLIENT_ID, "am-google");
info.put(RequestContext.KEY_FILTER_LEVEL, 3);
info.put(RequestContext.KEY_HTTP_USER_AGENT, "Android-Finsky/4.0.25 (api=3,versionCode=80200025,sdk=17,device=mako,hardware=mako,product=occam)");
info.put(RequestContext.KEY_LOGGING_ID, "");
info.put(RequestContext.KEY_SMALEST_SCREEN_WIDTH_DP, 384);
DfeContext context = new DfeContext(req);
DfeClient client = new DfeClient(context);

Now you should have a valid and running dfeclient. Depending on your setup, the AndroidContext and the UserAgent might be different The folowing is a sample code what could be done

Documents.BulkDetailsRequest.Builder request = Documents.BulkDetailsRequest.newBuilder();
request.addDocid("com.google.android.googlequicksearchbox");
request.setIncludeChildDocs(true);
client.requestBulkDetails(request.build());

And some possible interesting helper methods:

private static void dfeDownload(DfeClient client, String appId) throws IOException {
    DfeResponse<Documents.DetailsResponse> response = client.requestDetails(appId);
    DfeResponse<Unsorted.DeliveryResponse> deliveryResponse =
            client.requestDeliver(response.getResponse().getDocV2().getDocid(),
                                  response.getResponse().getDocV2().getDetails().getAppDetails().getVersionCode());
    if (deliveryResponse.getResponse() == null || deliveryResponse.getResponse().getStatus() == 3) {
        DfeResponse<Purchase.PurchaseStatusResponse> purchaseStatusResponse =
                client.requestPurchase(response.getResponse().getDocV2().getDocid(),
                                       response.getResponse().getDocV2().getDetails().getAppDetails()
                                               .getVersionCode());
        ParseToString.log(purchaseStatusResponse);
        deliveryResponse = client.requestDeliver(response.getResponse().getDocV2().getDocid(),
                                                 response.getResponse().getDocV2().getDetails().getAppDetails()
                                                         .getVersionCode());
    }
    downloadApk(deliveryResponse.getResponse().getAppDeliveryData().getDownloadUrl(),
                response.getResponse().getDocV2().getDocid() + "-" +
                response.getResponse().getDocV2().getDetails().getAppDetails().getVersionString() + ".apk",
                deliveryResponse.getResponse().getAppDeliveryData().getDownloadAuthCookieList());
}

private static void downloadApk(String url, String fileName, List<Download.HttpCookie> cookies) throws IOException {
    HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
    for (Download.HttpCookie cookie : cookies) {
        con.setRequestProperty("Cookie", cookie.getName() + "=" + cookie.getValue());
    }
    con.setDoInput(true);
    if (con.getResponseCode() != 200) {
        System.out.println("Error! " + con.getResponseMessage());
    } else {
        InputStream inputStream = con.getInputStream();
        FileOutputStream fos = new FileOutputStream(fileName);
        int n = con.getContentLength();
        byte[] buffer;
        while (n > 0) {
            buffer = new byte[Math.min(n, 1024)];
            int read = inputStream.read(buffer);
            fos.write(buffer, 0, read);
            n -= read;
        }
        inputStream.close();
        fos.close();
    }
}

Note: The things above are untested, but might work. As you might have seen my last commit is more than half a year ago and things might have changed. This API is far from complete yet - and maybe will never become complete.

mar-v-in avatar Jun 12 '14 19:06 mar-v-in

Hey there! this code seem quite old, I'm not able to compile with that, so following the structure I was able to download an application from play store with this:

public static final String KEY_AUTHORIZATION_TOKEN = "authToken";
public static final String KEY_ANDROID_ID_HEX = "androidIdHex";
public static final String KEY_FILTER_LEVEL = "filterLevel";
public static final String KEY_HTTP_USER_AGENT = "userAgent";

AndroidContext android = AndroidContext.baseDevice()
        .setEmail(GOOGLE_EMAIL)
        .setAndroidId(GOOGLE_GSF_ID)
        .buildClientId("am-android")
        .setCellOperator("31020", "T-Mobile");
    String authToken = new AndroidAuth().getAuthTokenResponse(android, GOOGLE_PASS, "androidmarket",
        "com.android.vending", "10321bd893f69af97f7573aafe9de1dc0901f3a1" /* Google's sig hash */,
        false, AuthType.Password).getData(DataField.AUTH_TOKEN);

    RequestContext req = new RequestContext();
    req.set(KEY_ANDROID_ID_HEX, android.getAndroidIdHex());
    req.set(KEY_AUTHORIZATION_TOKEN, authToken);
    req.set(KEY_FILTER_LEVEL, 3);
    req.set(KEY_HTTP_USER_AGENT,
        "Android-Finsky/4.0.25 (api=3,versionCode=80200025,sdk=17,device=mako,hardware=mako,product=occam)");
    DfeClient client = new DfeClient(req);
    AppDetails appDetails = client.details(appPackage).getResponse().docV2.details.appDetails;
    DfeResponse<DeliveryResponse> deliver = client.deliver(appPackage, appDetails.versionCode);

    if (deliver.getResponse() == null || (deliver.getResponse().status != null
        && deliver.getResponse().status == 3)) {
      client.purchase(appPackage, appDetails.versionCode);
      deliver = client.deliver(appPackage, appDetails.versionCode);
    }

    AndroidAppDeliveryData appDeliveryData = deliver.getResponse().appDeliveryData;

    downloadApk(appDeliveryData.downloadUrl, Environment.getExternalStorageDirectory()
        + "/"
        + appPackage
        + "-"
        + appDetails.versionCode
        + ".apk", appDeliveryData.downloadAuthCookie);

private static void downloadApk(String url, String fileName, List<HttpCookie> cookies)
      throws IOException {
    HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
    for (HttpCookie cookie : cookies) {
      con.setRequestProperty("Cookie", cookie.name + "=" + cookie.value);
    }
    con.setDoInput(true);
    if (con.getResponseCode() != 200) {
      System.out.println("Error! " + con.getResponseMessage());
    } else {
      InputStream inputStream = con.getInputStream();
      FileOutputStream fos = new FileOutputStream(fileName);
      int n = con.getContentLength();
      byte[] buffer;
      while (n > 0) {
        buffer = new byte[Math.min(n, 1024)];
        int read = inputStream.read(buffer);
        fos.write(buffer, 0, read);
        n -= read;
      }
      inputStream.close();
      fos.close();
    }
  }

GOOGLE_EMAIL, GOOGLE_PASS and GOOGLE_GSF_ID are your own data :+1:

Thanks for your hard work

PaNaVTEC avatar Aug 27 '15 07:08 PaNaVTEC

Hey Marvin, great code and thanks for your hard work! Just one small question, any idea inside Unsorted.proto, what are these "incremental" and "sideloadedAppCount" standing for? Many thanks!

vivijimmy avatar Oct 07 '15 10:10 vivijimmy