【问题标题】:How to get list of downloaded apps (paid/free) by a user from Google Play?如何从 Google Play 获取用户下载的应用程序(付费/免费)列表?
【发布时间】:2018-02-13 11:08:11
【问题描述】:

我最近遇到了这个应用程序Purchase Apps,在我使用我的谷歌帐户登录后,它能够以某种方式检索我在谷歌游戏中支付的应用程序。

我正在尝试了解它是如何完成的,因为我想构建一个类似的应用程序,但对于已下载的免费应用程序。

但是,即使在通过the entire list of APIs 之后,我也找不到用于检索该信息的 OAuth API 范围。


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

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

  1. 什么API可以用来获取已购买应用的信息?我在哪里可以读到它?请展示一个完整的工作示例。

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

  3. 使用此 API 有什么特殊要求吗?


编辑:我为此付出了最大的赏金,因为无论我阅读和尝试了多少,我仍然无法创建一个可以从 Play 商店查询用户曾经下载过的应用程序的 POC(名称、软件包名称、安装和/或删除日期、图标 URL、价格...),包括付费和免费应用程序。

如果有人找到了一个可行的示例,请说明它是如何完成的,并说明您是如何找到它的(文档或任何帮助您找到解决方案的东西)。我在任何地方都找不到它,而且这里的当前解决方案对我来说太模糊了。

【问题讨论】:

  • 我会查看示例应用程序启动器。它知道手机上下载了哪些应用程序。
  • @android 开发者:我已经通过反编译分析了Purchase Apps apk 文件。它从未使用任何 api 来获取已购买应用程序的列表。它的方法和我们知道的一样是解析play store网页的html内容。这是这段代码的一个片段:hastebin.com/uceyavurij.js
  • @aminography 那么它是如何为用户获取它的呢?毕竟,它需要获取用户 Google 帐户的数据……仅仅访问 Play 商店应用程序是不够的……它对赋予它的权限做了什么?
  • @androiddeveloper:Purchased Apps 提供的所有信息都可以从 Playstore Web 内容中检索到。不幸的是,我无法从 google play 购买应用程序。如果你分享给我一个有购买应用程序的帐户,我可以为你开发一个示例代码。

标签: android google-play google-oauth google-signin


【解决方案1】:

问题已解决。该漏洞利用已关闭。

由于登录的是 Android 预览版,我们将关闭此错误。如果问题在最新的公开版本 (Android Q) 中仍然相关且可重现,请捕获错误报告并将错误记录到 https://source.android.com/setup/contribute/report-bugs。如果在接下来的 14 天内未收到回复,此问题将被关闭。感谢您的理解。


最新更新:

这是一个错误,Google 将在下一次更新中解决它。

我们已将此问题推迟到将来的版本中考虑。谢谢 你花时间让 Android 变得更好


这个答案已经变成了一个想法的集合,并被编辑以包含来自 cmets 讨论的信息。

androidmarket api 将是开发人员编写的自定义api。它不向公众开放。

解决您在 cmets 中的疑虑。开发人员将利用 Android Developer 和 Google 提供的当前 API 来创建一个管理所有这些的项目。

至于访问Full Account Access,我不确定这些开发人员究竟是如何做到这一点的。

我建议使用AccountManager,它是android.accounts 的一部分,可以访问凭据和方法getUserData。帐户管理员有权访问密码,并能够创建和删除帐户。这个,可能和Content Provider一起使用

Udinic/SyncAdapter Authentication

回复您的评论:

此博客应该可以帮助您入门。 Write your own Android Authenticator


这些应用程序实际上是如何工作的,我无法告诉你。它们也可能有不同的实现(除非它们是幕后的协作,否则它们肯定会有所不同)。

一个猜测。首先使用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();

如果可以获得完全访问权限,则可以找到帐户持有人使用的所有应用的列表,并将其与设备上的内容进行比较。

Package Manager 将检索设备上当前安装的所有应用程序的列表。
PackageInfo 提供有关应用程序的详细信息。
INSTALL_REASON_USER 还会过滤掉用户主动安装的应用程序。

您可能想查看com.google.firebase.appindexingLog User Actions。可以跟踪不同的actions

用户帐户历史记录位于https://myactivity.google.com/myactivity

一个有用的链接是OAuth 2.0 Playground


这个 github repo node-google-play,使用节点,是最新的,将调用 Google Play API。就像被用作“非官方”API 的存档 android-market-api 来查询市场一样。


应用 1

app claims 使用以下权限:

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

其他

  • 从互联网接收数据
  • 查看网络连接
  • 完全网络访问
  • 在设备上使用帐号
  • 防止设备休眠
  • 读取谷歌服务配置

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

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


应用 2

您提到的另一个执行相同操作的应用程序更预先了解正在访问的内容。

My Paid Apps

安全/隐私声明
第一次运行此应用程序时,它会要求您获得 Google 帐户的完全权限。这是不幸的 访问所需信息的唯一方法。没有个人 信息已存储,不会与您共享有关您的应用程序的信息 此应用程序的开发者,也不与任何第三方共享。 一切都只保存在您的手机上。


我在this blog post 中详细介绍了这些应用程序,这是针对大学顶峰项目(没有金钱收益)。我倾向于认为这是 API 中的一个漏洞,而不是谷歌设计的状态,因为除了开发者自己的应用程序之外,没有 API 调用来获取应用程序的购买。我假设这是一个零日漏洞,在这种情况下,没有合法的方法可以访问这些信息。

【讨论】:

    【解决方案2】:

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

    简而言之,执行此操作的步骤如下:

    1. 登录: 上述程序的第一步是让用户登录并访问用户的访问令牌。为此,它使用android.accounts.AccountManager.getAuthToken() 方法。 (查看更多:AccountManager) 但是,对于令牌范围,需要oauth2:https://www.google.com/accounts/OAuthLogin。 可能需要注意的是,基于 Google 的 OAth2 documentation,此范围无效;但是,这似乎是 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 页面。

    以下是“Packet Capture”捕获的应用程序流量

    因为它在图片中清晰可见,最终结果与我通常使用 Chrome 桌面在我的 PC 上打开商店的帐户页面时得到的结果相同:

    旁注

    似乎没有记录这些端点,因为它们主要由 Google 自己的程序使用,应该被视为内部的。因此,我强烈建议不要在您希望长时间运行的任何程序或代码中或在生产环境中使用它们。 此外,这里也有一个坏消息,Google Play 的帐户页面似乎只列出了付费应用程序或特殊的免费应用程序(尤其是 OEM 应用程序)。我会试着找点时间深入研究其他应用程序。

    有趣的文章

    Pokemon tokens

    Exploiting Google Chrome's OAuth2 Tokens

    【讨论】:

    • 您能否展示一个完整的示例以了解其工作原理并回答我提出的问题?正如我所写,我想获取有关每个应用程序的各种信息:价格,购买时间等...是否也可以获取免费应用程序列表?
    【解决方案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))
    

    【讨论】:

      【解决方案4】:

      处理非官方的 Google API 是非常复杂的领域。 可能 让它工作,但这就是我要说的。风险自负。

      您需要做的第一件事是获取 Google Play 身份验证令牌。这可以通过多种方式完成,但在购买的应用程序中是这样的:

      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 商店端点。购买的应用程序使用的主要是https://android.clients.google.com/fdfe/purchaseHistory。您可能感兴趣的另一个是https://android.clients.google.com/fdfe/details?doc=(package name)(来自APKfetch code)。 Here's a page with some more and some analysis. 如果您向这些 API 发出请求,则需要提供几个标头:

      • Authorization - "GoogleLogin auth=(your auth token)"
      • 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 商店应用,并使用 JADX 之类的工具重用它们生成的 protobuf 模型。

      不幸的是,我已经尝试过了,但它并没有真正起作用。 Protobuf 模型类对于标准反编译器来说太复杂了。您可以使用一个名为PBTK 的工具。您最好在 Google Play Store 6.1.12 APK 上运行它,因为这是他们开始使用 ProGuard 之前的最后一个版本。请注意,该程序的脚本中有两个错误需要在运行前修复:将 gui.py 中的 'extracto' 更改为 'extractor' 并删除 第 500 行的断言语句>jar_extract.py

      现在,应该将所有响应类输出为 .proto 文件。在 src/main 下创建一个名为 proto 的文件夹并将整个生成的 'com' 目录拖到其中。您可以删除不在com/google/android/finsky/protos 下的所有内容。按照在线说明使用 Protobuf Lite 插件设置 Gradle。

      当您想要解析响应时,可以使用 ResponseWrapper 类,因为它们似乎都包含在该类之下。

      我能带你到这里就差不多了。我很有可能弄错了其中的一部分; JADX 是你最好的朋友,因为了解应用程序在做什么的最好方法是查看它的代码。希望这会有所帮助并祝您开发愉快!

      【讨论】:

      • 关于AccountManager,你确定它还在吗?我认为现在谷歌只提供使用 AccountPicker 的选项(比如这里:stackoverflow.com/a/26888259/878126)。但是我如何执行其余的?你测试过吗?它对你有用吗?请分享它的代码。这就是为什么我设置了一个赏金,看看它在行动......
      • 是的,AccountPicker 实际上是一个更好的主意。是的,我确实尝试了获取令牌的代码,并且效果很好。我还没有尝试过其他的,因为如果一切顺利的话,这至少需要 5 个小时的工作时间。即使是 500 的赏金也不值得。
      • 这里是获取身份验证令牌的完整代码(它的工作原理就像您屏幕截图中购买的应用程序一样):github.com/ethanblake4/PlayStoreDemo
      • 获取授权令牌似乎运作良好。但我认为困难的部分是应用程序本身的获取:(
      • 是的,不幸的是,这是需要大量工作的部分。但是,我反编译了已购买应用程序的代码,这就是它在那里完成的方式。如果您在上述步骤中需要帮助,请随时告诉我。
      【解决方案5】:

      您可以获取设备上所有已安装应用程序的软件包名称,然后从 google play 获取您在设备中找到的每个已安装软件包的信息,而无需访问用户帐户。有一些第三方或非官方 apis 通过获取应用程序包名称来获取 json 格式的 google play 应用程序详细信息。例如:https://42matters.com/ 然后使用收到的每个包裹的信息来找到免费的。

      【讨论】:

      • 不,我提出的问题是用户曾经安装过的应用程序,而不仅仅是现在安装的应用程序。另外,如果有官方的方式,为什么要使用非官方的...
      • @androiddeveloper 我猜没有官方 api 可以通过在 google play 中获取包名称来获取应用程序详细信息。有官方的api吗?
      • @androiddeveloper 谷歌会为每个用户保留已卸载的免费应用程序的名称吗?
      • 是的。如果您打开 Play 商店应用程序,请转到导航抽屉,然后转到“我的应用程序和游戏”。您将在那里看到您曾经安装过的所有应用程序,而不仅仅是当前安装的应用程序。根据谷歌的说法,允许(或者至少他们似乎这么说)使用这个 API:issuetracker.google.com/issues/79195087。或者,与我交谈的人都不熟悉那里发生的事情......
      【解决方案6】:

      我有两个资源供您考虑,但首先,总而言之,没有。 GOOGLE 没有 api 让你做你想做的事,因为这些指标没有存储在手机中,它们在 google play store 服务器上,google 没有用于 play store 的官方 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

      这足以了解如何实现这一点。

      首先,一个帐户下载了哪些应用程序的列表只能由该帐户引用。这可以通过游戏商店完成。由于您的应用将安装在该用户的手机上,因此这无关紧要……您就在其中。

      其次,您需要为 GOOGLE PLAY STORE 构建的第 3 方 API,那里有一些,请查看第一个链接。

      使用您选择的 api,您将向 play 商店发送一个 get 请求,作为回报,在大多数情况下您应该收到一个要反序列化的 json 对象。

      反序列化对象,你就会得到你的列表。您获得的列表取决于您使用的端点,但这应该由 API 本身解释。

      祝你好运!

      【讨论】:

      • 在所有链接中,我没有看到一个获取当前用户安装的应用程序列表的链接。他们甚至没有登录阶段。它们都收集有关应用程序的一般信息,无论用户是否安装了它们。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-07-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多