Skip to content
This repository has been archived by the owner on Jun 25, 2020. It is now read-only.

How-to docs #3

Open
gergelyke opened this issue Jun 12, 2014 · 3 comments
Open

How-to docs #3

gergelyke opened this issue Jun 12, 2014 · 3 comments

Comments

@gergelyke
Copy link

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

@mar-v-in
Copy link
Member

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.

@PaNaVTEC
Copy link

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 👍

Thanks for your hard work

@vivijimmy
Copy link

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!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants