如何从Google Play获取用户已下载应用程序的列表(包括付费和免费应用)?

120
我最近发现了这个应用购买应用程序,在我使用谷歌账户登录后,它能够检索到我在Google Play上购买的应用程序。
我正在尝试找出它是如何实现的,因为我想构建一个类似的应用程序,但是针对已下载的免费应用程序。
然而,即使查看整个API列表,我也找不到用于检索该信息的OAuth API范围。

Google Sign in asking for access to androidmarket


编辑:

我正在这个问题上放置一个新的赏金,如我关于here的类似问题所建议的那样,并且因为在这里和那里我没有看到真正的答案关于如何做到这一点,以及可以用它做什么。

我想将问题细化为多个部分:

  1. 可以用于获取已购应用程序信息的API是什么?在哪里可以阅读有关它的信息?请展示一个完整的、可行的例子来说明如何做到这一点。

  2. 它还能做更多吗?也许执行搜索?也许显示已安装的免费应用程序?也许显示它们安装和卸载的时间?以及这些应用程序的类别?

  3. 使用此API是否有任何特殊要求?


编辑:我在这里设置了最高赏金,因为无论我读了多少并尝试过多少次,我仍然未能制作出一个可以查询用户曾经下载的应用程序(名称、包名、安装和/或删除日期、图标URL、价格等)的POC,包括付费和免费应用。

如果有人找到一个可行的样本,请展示如何完成,并展示您是如何发现它的(文档或任何导致您找到解决方案的内容)。我无法在任何地方找到它,而且这里的当前解决方案对我来说太模糊了,无法开始。


尝试访问此存储库 https://github.com/googlesamples/android-play-publisher-api/tree/master/v3/java - Codelaby
我会查看示例应用程序启动器。它知道手机上下载了哪些应用程序。 - danny117
@安卓开发者:我通过反编译分析了“购买应用”apk文件。它从未使用任何api来获取已购买应用程序列表。它的方法与我们所知道的相同,即解析Play商店网页的HTML内容。这是代码片段:https://hastebin.com/uceyavurij.js - aminography
@aminography 那么它如何为用户获取数据呢?毕竟,它需要获取用户Google账户的数据...仅仅访问Play Store应用是不够的... 它会如何处理获得的权限呢? - android developer
@androiddeveloper:已购应用程序提供的所有信息都可以从Play商店网页内容中检索。不幸的是,我无法购买Google Play上的应用程序。如果您与我分享一个拥有已购应用程序的帐户,我可以为您开发示例代码。 - aminography
显示剩余4条评论
6个回答

51
问题已经解决,漏洞已经关闭。
我们将关闭此漏洞,因为它是在 Android 预览版中记录的。如果该问题仍然与最新公共版本(Android Q)相关且可重现,请捕获一个错误报告并在https://source.android.com/setup/contribute/report-bugs中记录该错误。如果在接下来的14天内没有收到回复,则此问题将被关闭。谢谢您的理解。
最新更新:
这是一个错误,谷歌将在下一次更新中解决它。

我们已经推迟了这个问题,以便在未来的版本中考虑。感谢您花时间使Android变得更好。


这个答案已经变成了各种想法的混合体,并被编辑以包括评论中的信息。
androidmarket api 将是开发人员编写的定制化 api,不向公众开放。
开发人员将利用 Android Developer 和 Google 提供的当前 api 创建一个项目来管理所有这些事项,以解决您在评论中提出的问题。
至于如何访问完整帐户访问权限,我不确定这些开发人员是如何实现的。
我建议使用 android.accounts 中的 AccountManager,它具有访问凭据和 getUserData 方法。账户管理员可以访问密码,能够创建和删除帐户。这可能与 Content Provider 一起使用。
请看Udinic/SyncAdapter Authentication
回复你的评论:
这篇博客应该能帮助你入门。编写自己的Android身份验证器
这些应用程序的实际工作原理,我无法告诉您。它们可能也有不同的实现(除非在幕后进行协作努力,否则它们肯定会有所不同)。
一个猜测是,首先使用GoogleSignInAccountcom.google.android.gms.auth.api.signin
有一个scope的定义,以确定应用程序被授予的权限范围。
使用requestScopes()public static final String PROFILE 它让您的网络应用程序可以访问通过空中安装的Android应用程序。针对example
GoogleSignInOptions gso =
        new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestEmail().
            .requestScopes(new Scope("https://www.googleapis.com/auth/contacts.readonly"))
            .build();

如果完全访问权限被获得,可以找到账户持有人使用的所有应用程序列表,并与设备上的应用程序进行比较。 包管理器将检索设备上当前安装的所有应用程序列表。
PackageInfo提供有关应用程序的详细信息。
INSTALL_REASON_USER还将过滤出用户主动安装的应用程序。
您可能需要查看com.google.firebase.appindexingLog User Actions。不同的操作可以被跟踪。
用户账户历史记录可在https://myactivity.google.com/myactivity中找到。
一个有用的链接是 OAuth 2.0 Playground
这个 Github 仓库 node-google-play 使用 Node,并且是最新的,可以调用 Google Play 的 API。就像之前使用过的“非官方”API android-market-api 一样,可以查询应用市场。

应用程序1

该应用程序 声称使用以下权限:

版本2.1.8可以访问:
$ 应用内购买

其他

  • 接收互联网数据
  • 查看网络连接
  • 完全的网络访问权限
  • 使用设备上的帐户
  • 防止设备休眠
  • 读取Google服务配置

值得注意的是,当进行基本安装时,该应用程序不设置任何权限。由于我没有付费应用程序,因此无法使用任何功能。因此,在最初的搜索中 - 没有需要的权限,这表明该应用程序无法访问我的帐户。

我检查了权限 - 没有设置任何权限。因此,唯一需要的是接受弹出窗口,如您的问题所示。


应用程序 2

你提到的另一个执行同样功能的应用程序更加明确正在访问的内容。

我的付费应用

安全/隐私注意事项
第一次运行此应用程序时,它将要求完整访问您的Google帐户。不幸的是,这是访问所需信息的唯一方法。没有存储个人信息,也没有与此应用程序的开发人员或任何第三方共享应用程序信息。所有信息仅保存在您的手机上。


我在这篇博客文章中详细介绍了这些应用程序,该文章是为大学顶峰项目(无经济利益)而撰写的。我倾向于认为这是API中的漏洞,而不是Google设计上的状态,因为除了开发者自己的应用程序之外,没有API调用来获取其他应用程序的购买情况。我假设这是一个零日漏洞,如果是这样,就没有合法的方法可以访问这些信息。

10

针对这些应用程序中的一个(我的付费应用程序),在检查网络流量后,很明显它确实使用商店的帐户页面来检索有关已付费应用程序的列表。现在,它使用的机制与Google Chrome当前使用的机制以及Pokemon GO据称在某个时间点使用的机制相同。

简而言之,操作步骤如下:

  1. 登录:该程序的第一步是让用户登录并获取用户的访问令牌。为此,它使用了android.accounts.AccountManager.getAuthToken()方法。(更多信息请参见:AccountManager)然而,对于令牌范围,请求的是oauth2:https://www.google.com/accounts/OAuthLogin。需要注意的是,根据OAth2文档来看,这个范围是无效的;但是,它似乎是Google OAuth v1的一个有效范围。

  2. 将新获取的访问令牌转换为ubertoken现在,实际上ubertoken应该做什么是未知的,也没有官方的文档介绍。然而,在野外发现它被Chrome浏览器用于登录用户。这是通过请求https://accounts.google.com/OAuthLogin?source=ChromiumBrowser&issueuberauth=1页面完成的。

  3. ubertoken转换为网站会话:随后,使用新创建的ubertoken可以使用https://accounts.google.com/MergeSession API端点获取网站会话。此步骤完成后,应用程序基本上能够加载您在登录状态下可以使用浏览器打开的所有个人页面;除了一些特殊页面,包括付款设置。

  4. 检索付费应用程序列表:请求并解析https://play.google.com/store/account页面。

以下是由'数据包捕获'捕获的应用程序流量:

Captured Traffic

如图片所示,使用Chrome桌面版在我的电脑上正常打开商店账户页面所得到的最终结果与此相同: Chrome view source

附注

这些端点似乎都未被记录,因为它们主要由Google自己的程序使用,并且应被视为内部。因此,我强烈建议不要在预计长时间运行或在生产环境中运行的任何程序或代码中使用它们。 同时,对于您来说也有一个坏消息,看起来Google Play的帐户页面仅列出付费应用程序或特殊免费应用程序(更特别是OEM应用程序)。我将尽力挤出时间深入挖掘其他应用程序。

有趣的文章:

Pokemon tokens

Exploiting Google Chrome's OAuth2 Tokens


1
请问您能否提供一个完整的示例以便我了解它是如何工作的,并回答我所提出的问题吗?正如我所写的,我想获取有关每个应用程序的各种信息:价格、购买时间等等...是否也可以获取免费应用程序的列表? - android developer

3
如果您拥有root权限,您可以访问 /data/data/com.android.vending/databases/library.db
OnePlus3T:/data/data/com.android.vending/databases
-rw-rw---- 1 u0_a2 u0_a2 229376 2018-12-26 18:01 library.db

这个数据库包含了所有信息,包括你下载过哪些应用程序,购买了哪些应用程序,甚至在哪个应用程序中进行了 IAP

查看所有权表,它包含了所有信息。

ownership (account STRING, library_id STRING, backend INTEGER, doc_id STRING, doc_type INTEGER, offer_type INTEGER, document_hash INTEGER, subs_valid_until_time INTEGER, app_certificate_hash STRING, app_refund_pre_delivery_endtime_ms INTEGER, app_refund_post_delivery_window_ms INTEGER, subs_auto_renewing INTEGER, subs_initiation_time INTEGER, subs_trial_until_time INTEGER, inapp_purchase_data STRING, inapp_signature STRING, preordered INTEGER, owned_via_license INTEGER, shared_by_me INTEGER, sharer_gaia_id TEXT, shareability INTEGER, purchase_time INTEGER, PRIMARY KEY (account, library_id, backend, doc_id, doc_type, offer_type))

2
处理非官方的 Google API 是非常复杂的领域。虽然有可能让它工作,但这就是我要说的全部了。请自行决定是否继续。
首先,你需要获取一个 Google Play 授权令牌。有几种方法可以实现,但以下是 Purchased Apps 使用的方法:
public static String getAuthToken(Activity activity, String userEmail) {

    AccountManager accountManager = AccountManager.get(activity);
    Account userAccount = new Account(userEmail, "com.google");

    Bundle options = new Bundle();
    options.putBoolean("suppressProgressScreen", true);

    String token;

    try {
      Bundle result = accountManager
        .getAuthToken(userAccount, "androidmarket", options, activity, null, null)
        .getResult();
      token = result.getString("authtoken");
    } catch (OperationCanceledException e) {
      Log.d(TAG, "Login canceled by user");
      return null;
    } catch (IOException | AuthenticatorException e) {
      Log.e(TAG, "Login failed", e);
      return null;
    }

    return token;
}

一些需要注意的事项:
  • 以上代码必须以异步方式运行。我建议使用RxJava,但AsyncTask也可以。
  • 您必须为要使用的帐户提供电子邮件。我会把细节留给您,但使用AccountManager相当容易。

在获得授权令牌后,您现在可以访问任何Google Play Store端点。Purchased Apps使用的主要端点是https://android.clients.google.com/fdfe/purchaseHistory。另一个可能会让您感兴趣的是https://android.clients.google.com/fdfe/details?doc=(package name)(来自APKfetch code)。这里有一些更多的信息和分析。如果您向这些API发出请求,您将需要提供几个标头:

  • Authorization - "GoogleLogin auth=(您的授权令牌)"
  • User-Agent - "Android-Finsky/6.4.12.C-all%20%5B0%5D%202744941 (api=3,versionCode=80641200,sdk=" + VERSION.SDK_INT + ",isWideScreen=0)";
  • X-DFE-Device-Id - 您设备的 Google 服务框架 ID,从 AdvertisingIdClient 获取。
  • X-DFE-Client-Id - "am-android-google"
  • Accept-Language - 设备的语言代码,例如 "en"
现在,您需要解析响应。这就是事情变得棘手的地方。这些API返回的消息被编码为Protobuf,因此它本质上只是二进制数据,除非您有模式(当然,只有Google才有)。理论上处理这个问题的一种方法是反编译Google Play Store应用程序,并使用类似于JADX的工具重新使用它们生成的protobuf模型。
不幸的是,我已经尝试过这个方法,但它并没有真正起作用。 Protobuf模型类对于标准反编译器来说太复杂了。您可以使用一个名为PBTK的工具。最好在Google Play Store 6.1.12 APK上运行此程序,因为这是他们开始使用ProGuard之前的最后一个版本。请注意,在运行此程序之前,需要修复其脚本中的两个错误:在gui.py中将'extracto'更改为'extractor',并删除jar_extract.py的第500行上的断言语句。
现在,应该将所有的响应类输出为.proto文件。在src/main下创建一个名为proto的文件夹,并将整个生成的'com'目录拖到其中。您可以删除不属于com/google/android/finsky/protos的所有内容。按照在线说明设置Gradle与Protobuf Lite插件。
当您想要解析响应时,可以使用ResponseWrapper类,因为它们似乎都包含在其中。
这大概就是我能带给你的了。我可能有错误的地方;JADX是您在这里最好的朋友,因为了解应用程序正在做什么的最佳方法是查看其代码。希望这有所帮助,祝您开发愉快!

关于 AccountManager,你确定它还可用吗?我认为现在谷歌只提供使用 AccountPicker 的选项(就像这里:https://dev59.com/ZnI95IYBdhLWcg3w3yFU#26888259)。但是我该如何执行其余部分呢?你测试过了吗?它对你有效吗?请分享代码。这就是我设置赏金的原因,想看到它实际运行... - android developer
是的,使用AccountPicker是一个更好的想法。而且,我确实尝试了获取令牌的代码,它运行得非常好。但是,说实话,如果一切顺利,我还没有尝试过其他部分,因为那至少需要5个小时的工作时间。即使是500美元的赏金也不值得这样做。 - qualverse
1
这是获取授权令牌的完整代码(它的工作方式就像您截图中购买的应用程序一样):https://github.com/ethanblake4/PlayStoreDemo - qualverse
获取认证令牌似乎很顺利。但我认为困难的部分是获取应用本身 :( - android developer
是的,不幸的是,那就是需要花费很多工作量的部分。不过,我已经反编译了“已购应用程序”的代码,那就是它的实现方式。如果你需要上述步骤的帮助,请随时告诉我。 - qualverse

-2

您可以获取设备上所有已安装应用的包名,然后从 Google Play 获取在设备中找到的每个已安装包的信息,无需登录用户帐户即可进行操作。还有一些第三方或非官方API可以通过获取应用程序包名称以json格式获取 Google Play 应用程序详情。例如:https://42matters.com/ 然后使用每个包接收到的信息来查找免费应用。


不,我设置悬赏的问题是关于用户曾经安装过的应用程序,而不仅仅是现在已安装的应用程序。此外,如果有官方途径,为什么要使用非官方的方法... - android developer
@androiddeveloper 我猜在谷歌商店中,没有官方API可以通过包名获取应用详细信息。请问是否有官方API可供使用? - ygngy
@androiddeveloper Google会为每个用户保留已卸载的免费应用程序的名称吗? - ygngy
是的。如果您打开Play商店应用程序,转到导航抽屉,然后转到“我的应用和游戏”。您将在那里看到所有您曾经从那里安装过的应用程序,而不仅仅是当前安装的应用程序。根据谷歌的说法,使用此API是允许的(或者至少他们似乎是这样说的):https://issuetracker.google.com/issues/79195087。或者,与我交谈的人不熟悉那里正在发生的事情... - android developer

-2
我有两个资源供您考虑,但首先,简单来说,没有。谷歌没有提供API让您做想要的事情,因为这些指标不是存储在手机上的,而是存储在Google Play商店服务器上,而且Google没有官方的Play商店API。但是,您可以从以下这两个网站中获取一些信息:

https://www.quora.com/Is-there-an-API-for-the-Google-Play-Storeenter link description here

https://android.stackexchange.com/questions/162146/how-to-see-all-the-apps-i-have-downloaded-from-google-play-store

这就足以展示如何完成这个任务了。

首先,账户下载的应用列表只能由该账户引用。并且可以通过Play商店来实现。既然你的应用程序将安装在用户的手机上,那么这就不重要了...... 你成功了。

其次,你需要一个第三方API,用于GOOGLE PLAY STORE,市场上有一些,可以查看第一个链接。

使用你选择的API,向Play商店发送一个get请求,通常会返回一个json对象进行反序列化。

反序列化对象,你就得到了一个列表。所获得的列表取决于你使用的终端节点,但这应该在API本身中进行解释。

祝你好运!


在所有的链接中,我没有看到一个可以获取当前用户安装的应用程序列表的链接。它们甚至没有登录阶段。所有这些链接都收集有关应用程序的通用信息,无论用户是否安装了它们。 - android developer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接