【问题标题】:How to get app market version information from google play store?如何从 google play store 获取应用市场版本信息?
【发布时间】:2016-03-22 10:39:44
【问题描述】:

如何从谷歌游戏商店获取应用程序版本信息,以便在更新 Play 商店应用程序时提示用户强制/推荐应用程序更新,即如果用户使用旧版本应用程序。我已经通过andorid-market-api 这不是官方的方式,还需要来自google 的oauth login 身份验证。我也经历过android query 它提供应用内版本检查,但在我的情况下不起作用。 我找到了以下两种选择:

  • 使用将存储版本信息的服务器 API
  • 使用谷歌标签并在应用内访问它,这不是首选方式。

还有其他方法可以轻松做到吗?

【问题讨论】:

  • 我更喜欢你的第一种方式...
  • @CapDroid 还有其他方法吗?尤其是在独立应用的情况下。
  • 我不知道 :( 主要是我按照你的第一种方式 :)
  • 采取第一种方法,虽然学习会很有趣,如果有其他选择的话。好问题!

标签: android version-control google-play google-apps-marketplace google-play-developer-api


【解决方案1】:

我建议不要使用库,只需创建一个新类

1.

public class VersionChecker extends AsyncTask<String, String, String>{

String newVersion;

@Override
protected String doInBackground(String... params) {

    try {
        newVersion = Jsoup.connect("https://play.google.com/store/apps/details?id=" + "package name" + "&hl=en")
                .timeout(30000)
                .userAgent("Mozilla/5.0 (Windows; U; WindowsNT 5.1; en-US; rv1.8.1.6) Gecko/20070725 Firefox/2.0.0.6")
                .referrer("http://www.google.com")
                .get()
                .select("div.hAyfc:nth-child(4) > span:nth-child(2) > div:nth-child(1) > span:nth-child(1)")
                .first()
                .ownText();
    } catch (IOException e) {
        e.printStackTrace();
    }

    return newVersion;
}
  1. 在你的活动中:

        VersionChecker versionChecker = new VersionChecker();
        String latestVersion = versionChecker.execute().get();
    

就是这样

【讨论】:

  • 这是一个黑客。但这是一个非常好的 hack,不需要太多努力,特别是考虑到 Google 很难使用他们的 api。 +1。 :)
  • 这只是坏了。如果您使用正则表达式,则可以使用 &lt;div[^&gt;]*?&gt;Current Version&lt;/div&gt;&lt;div&gt;&lt;span[^&gt;]*?&gt;(.*?)&lt;/span&gt;&lt;/div&gt;
  • 对于android用户在gradle文件中添加这个依赖,编译'org.jsoup:jsoup:1.11.3'
  • 这也是通过用户的移动数据连接下载大量 HTML 数据(截至目前为 780 KB)。并非每个人都在加利福尼亚并且拥有无限数据计划。这段代码不仅不健壮,而且对用户来说也是一个巨大的麻烦。
【解决方案2】:

旧版本(不再工作)

这里是 jQuery 版本,如果其他人需要,可以获取版本号。

    $.get("https://play.google.com/store/apps/details?id=" + packageName + "&hl=en", function(data){
        console.log($('<div/>').html(data).contents().find('div[itemprop="softwareVersion"]').text().trim());
    });

当前解决方案

使用 PHP 后端。这已经工作了一年。似乎 Google 不会经常更改他们的 DOM。

public function getAndroidVersion(string $storeUrl): string
{
    $dom = new DOMDocument();
    $dom->loadHTML(file_get_contents($storeUrl));
    libxml_use_internal_errors(false);
    $elements = $dom->getElementsByTagName('span');

    $depth = 0;
    foreach ($elements as $element) {
        foreach ($element->attributes as $attr) {
            if ($attr->nodeName === 'class' && $attr->nodeValue === 'htlgb') {
                $depth++;
                if ($depth === 7) {
                    return preg_replace('/[^0-9.]/', '', $element->nodeValue);
                    break 2;
                }
            }
        }
    }
}

【讨论】:

  • 我需要离子,但是当我使用它时会出现一些 cors 问题,
  • 这是超级易碎的。我怎么知道?我继承的一个应用程序就是这样做的,今天已经开始hard崩溃了。
  • 我在这个命令的输出中没有看到softwareVersion。应该是变了
  • @Gi0rgi0s 这已经很久没有工作了。你的 DOM 已经很稳定了。我一直在解析DOM。目前正在寻找课程:htlgb
【解决方案3】:

使用此代码可以正常工作。

public void forceUpdate(){
    PackageManager packageManager = this.getPackageManager();
    PackageInfo packageInfo = null;
    try {
        packageInfo =packageManager.getPackageInfo(getPackageName(),0);
    } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
    }
    String currentVersion = packageInfo.versionName;
    new ForceUpdateAsync(currentVersion,TodayWork.this).execute();
}

public class ForceUpdateAsync extends AsyncTask<String, String, JSONObject> {

    private String latestVersion;
    private String currentVersion;
    private Context context;
    public ForceUpdateAsync(String currentVersion, Context context){
        this.currentVersion = currentVersion;
        this.context = context;
    }

    @Override
    protected JSONObject doInBackground(String... params) {

        try {
            latestVersion = Jsoup.connect("https://play.google.com/store/apps/details?id=" + context.getPackageName()+ "&hl=en")
                    .timeout(30000)
                    .userAgent("Mozilla/5.0 (Windows; U; WindowsNT 5.1; en-US; rv1.8.1.6) Gecko/20070725 Firefox/2.0.0.6")
                    .referrer("http://www.google.com")
                    .get()
                    .select("div.hAyfc:nth-child(3) > span:nth-child(2) > div:nth-child(1) > span:nth-child(1)")
                    .first()
                    .ownText();
            Log.e("latestversion","---"+latestVersion);

        } catch (IOException e) {
            e.printStackTrace();
        }
        return new JSONObject();
    }

    @Override
    protected void onPostExecute(JSONObject jsonObject) {
        if(latestVersion!=null){
            if(!currentVersion.equalsIgnoreCase(latestVersion)){
                // Toast.makeText(context,"update is available.",Toast.LENGTH_LONG).show();
                if(!(context instanceof SplashActivity)) {
                    if(!((Activity)context).isFinishing()){
                        showForceUpdateDialog();
                    }
                }
            }
        }
        super.onPostExecute(jsonObject);
    }

    public void showForceUpdateDialog(){

        context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + context.getPackageName())));
    }

}

【讨论】:

    【解决方案4】:

    Firebase 远程配置可以在这里提供最佳帮助,

    请参考这个答案 https://stackoverflow.com/a/45750132/2049384

    【讨论】:

      【解决方案5】:

      我怀疑请求应用程序版本的主要原因是提示用户更新。我不赞成抓取响应,因为这可能会破坏未来版本的功能。

      如果应用最低版本为5.0,可以根据文档https://developer.android.com/guide/app-bundle/in-app-updates实现应用内更新

      如果请求应用版本的原因不同,您仍然可以使用 appUpdateManager 来检索版本并做任何您想做的事情(例如将其存储在首选项中)。

      例如我们可以将文档的 sn-p 修改成这样的:

      // Creates instance of the manager.
      val appUpdateManager = AppUpdateManagerFactory.create(context)
      
      // Returns an intent object that you use to check for an update.
      val appUpdateInfoTask = appUpdateManager.appUpdateInfo
      
      // Checks that the platform will allow the specified type of update.
      appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
          val version = appUpdateInfo.availableVersionCode()
          //do something with version. If there is not a newer version it returns an arbitary int
      }
      

      【讨论】:

      • 最佳解决方案,这是获取应用更新信息的官方方式
      【解决方案6】:

      除了使用 JSoup,我们还可以通过模式匹配从 playStore 获取应用版本。

      要匹配来自 google playstore 的最新模式,即 &lt;div class="BgcNfc"&gt;Current Version&lt;/div&gt;&lt;span class="htlgb"&gt;&lt;div&gt;&lt;span class="htlgb"&gt;X.X.X&lt;/span&gt;&lt;/div&gt; 我们首先必须匹配上面的节点序列,然后从上面的序列中获取版本值。下面是相同的代码sn-p:

          private String getAppVersion(String patternString, String inputString) {
              try{
                  //Create a pattern
                  Pattern pattern = Pattern.compile(patternString);
                  if (null == pattern) {
                      return null;
                  }
      
                  //Match the pattern string in provided string
                  Matcher matcher = pattern.matcher(inputString);
                  if (null != matcher && matcher.find()) {
                      return matcher.group(1);
                  }
      
              }catch (PatternSyntaxException ex) {
      
                  ex.printStackTrace();
              }
      
              return null;
          }
      
      
          private String getPlayStoreAppVersion(String appUrlString) {
              final String currentVersion_PatternSeq = "<div[^>]*?>Current\\sVersion</div><span[^>]*?>(.*?)><div[^>]*?>(.*?)><span[^>]*?>(.*?)</span>";
              final String appVersion_PatternSeq = "htlgb\">([^<]*)</s";
              String playStoreAppVersion = null;
      
              BufferedReader inReader = null;
              URLConnection uc = null;
              StringBuilder urlData = new StringBuilder();
      
              final URL url = new URL(appUrlString);
              uc = url.openConnection();
              if(uc == null) {
                 return null;
              }
              uc.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; WindowsNT 5.1; en-US; rv1.8.1.6) Gecko/20070725 Firefox/2.0.0.6");
              inReader = new BufferedReader(new InputStreamReader(uc.getInputStream()));
              if (null != inReader) {
                  String str = "";
                  while ((str = inReader.readLine()) != null) {
                                 urlData.append(str);
                  }
              }
      
              // Get the current version pattern sequence 
              String versionString = getAppVersion (currentVersion_PatternSeq, urlData.toString());
              if(null == versionString){ 
                  return null;
              }else{
                  // get version from "htlgb">X.X.X</span>
                  playStoreAppVersion = getAppVersion (appVersion_PatternSeq, versionString);
              }
      
              return playStoreAppVersion;
          }
      

      我通过这个解决了这个问题。这也解决了 Google 在 PlayStore 中所做的最新更改。希望对您有所帮助。

      【讨论】:

      • 我将在您的许可下使用 AsynsTask 发布完整代码
      • 不中继“当前版本”这个词更健壮,因为用户可能有不同的区域偏好
      【解决方案7】:

      使用将存储版本信息的服务器 API

      如您所说。这是检测更新的简单方法。在每个 API 调用中传递您的版本信息。当 playstore 更新时,更改服务器中的版本。一旦服务器版本高于安装的应用程序版本,您可以在 API 响应中返回一个状态代码/消息,可以处理并显示更新消息。 如果您使用此方法,您还可以阻止用户使用 WhatsApp 等非常旧的应用程序。

      或者你可以使用推送通知,这很容易做到......也

      【讨论】:

      【解决方案8】:

      此解决方案的完整源代码:https://stackoverflow.com/a/50479184/5740468

      import android.os.AsyncTask;
      import android.support.annotation.Nullable;
      
      import java.io.BufferedReader;
      import java.io.IOException;
      import java.io.InputStreamReader;
      import java.net.URL;
      import java.net.URLConnection;
      import java.util.regex.Matcher;
      import java.util.regex.Pattern;
      import java.util.regex.PatternSyntaxException;
      
      public class GooglePlayAppVersion extends AsyncTask<String, Void, String> {
      
          private final String packageName;
          private final Listener listener;
          public interface Listener {
              void result(String version);
          }
      
          public GooglePlayAppVersion(String packageName, Listener listener) {
              this.packageName = packageName;
              this.listener = listener;
          }
      
          @Override
          protected String doInBackground(String... params) {
              return getPlayStoreAppVersion(String.format("https://play.google.com/store/apps/details?id=%s", packageName));
          }
      
          @Override
          protected void onPostExecute(String version) {
              listener.result(version);
          }
      
          @Nullable
          private static String getPlayStoreAppVersion(String appUrlString) {
              String
                    currentVersion_PatternSeq = "<div[^>]*?>Current\\sVersion</div><span[^>]*?>(.*?)><div[^>]*?>(.*?)><span[^>]*?>(.*?)</span>",
                    appVersion_PatternSeq = "htlgb\">([^<]*)</s";
              try {
                  URLConnection connection = new URL(appUrlString).openConnection();
                  connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; WindowsNT 5.1; en-US; rv1.8.1.6) Gecko/20070725 Firefox/2.0.0.6");
                  try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
                      StringBuilder sourceCode = new StringBuilder();
                      String line;
                      while ((line = br.readLine()) != null) sourceCode.append(line);
      
                      // Get the current version pattern sequence
                      String versionString = getAppVersion(currentVersion_PatternSeq, sourceCode.toString());
                      if (versionString == null) return null;
      
                      // get version from "htlgb">X.X.X</span>
                      return getAppVersion(appVersion_PatternSeq, versionString);
                  }
      
              } catch (IOException e) {
                  e.printStackTrace();
              }
              return null;
          }
      
          @Nullable
          private static String getAppVersion(String patternString, String input) {
              try {
                  Pattern pattern = Pattern.compile(patternString);
                  if (pattern == null) return null;
                  Matcher matcher = pattern.matcher(input);
                  if (matcher.find()) return matcher.group(1);
              } catch (PatternSyntaxException e) {
                  e.printStackTrace();
              }
              return null;
          }
      
      }
      

      用法:

      new GooglePlayAppVersion(getPackageName(), version -> 
          Log.d("TAG", String.format("App version: %s", version)
      ).execute();
      

      【讨论】:

        【解决方案9】:

        服务器端用户版本 API:

        这是目前获得市场版本的最佳方式。当您将上传新的 apk 时,请更新 api 中的版本。因此,您将在您的应用程序中获得最新版本。 - 这是最好的,因为没有 google api 来获取应用版本。

        使用 Jsoup 库:

        这基本上是网络抓取。这不是一种方便的方法,因为如果谷歌更改了他们的代码,这个过程将不起作用。虽然可能性很小。无论如何,要获得带有 Jsop 库的版本。

        1. 在你的 build.gradle 中添加这个库

          实现'org.jsoup:jsoup:1.11.1'

        2. 为版本检查创建一个类:

        导入 android.os.AsyncTask 导入 o​​rg.jsoup.Jsoup 导入 java.io.IOException

        类 PlayStoreVersionChecker(private val packageName: String) : 异步任务() {

        private var playStoreVersion: String = ""
        
        override fun doInBackground(vararg params: String?): String {
            try {
                playStoreVersion =
                        Jsoup.connect("https://play.google.com/store/apps/details?id=$packageName&hl=en")
                            .timeout(30000)
                            .userAgent("Mozilla/5.0 (Windows; U; WindowsNT 5.1; en-US; rv1.8.1.6) Gecko/20070725 Firefox/2.0.0.6")
                            .referrer("http://www.google.com")
                            .get()
                            .select("div.hAyfc:nth-child(4) > span:nth-child(2) > div:nth-child(1) > span:nth-child(1)")
                            .first()
                            .ownText()
            } catch (e: IOException) {
            }
            return playStoreVersion
        } }
        
        1. 现在使用类如下:

          val playStoreVersion = PlayStoreVersionChecker("com.example").execute().get()

        【讨论】:

          【解决方案10】:

          对于 PHP 它有助于 php 开发人员获取特定 play store 应用服务器端的版本代码

          $package='com.whatsapp';
                  $html = file_get_contents('https://play.google.com/store/apps/details?id='.$package.'&hl=en');
                  preg_match_all('/<span class="htlgb"><div class="IQ1z0d"><span class="htlgb">(.*?)<\/span><\/div><\/span>/s', $html, $output);
          print_r($output[1][3]);
          

          【讨论】:

          • 虽然这段代码可以解决问题,including an explanation 解决问题的方式和原因,特别是当问题有多个好的答案时,确实有助于提高帖子的质量,并且可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的答案以添加解释并说明适用的限制和假设。 From Review
          【解决方案11】:

          我会推荐使用 ex。推送通知以通知您的应用程序有新更新,或者使用您自己的服务器从那里启用您的应用程序读取版本。

          是的,每次更新您的应用程序时都会有额外的工作,但在这种情况下,您不依赖于可能会停止服务的某些“非官方”或第三方的东西。

          以防万一您遗漏了什么 - 之前对您的主题的讨论 query the google play store for the version of an app?

          【讨论】:

          【解决方案12】:

          您可以调用以下WebService: http://carreto.pt/tools/android-store-version/?package=[YOUR_APP_PACKAGE_NAME]

          使用 Volley 的示例:

          String packageName = "com.google.android.apps.plus";
          String url = "http://carreto.pt/tools/android-store-version/?package=";
          JsonObjectRequest jsObjRequest = new JsonObjectRequest
              (Request.Method.GET, url+packageName, null, new Response.Listener<JSONObject>() {
                              @Override
                              public void onResponse(JSONObject response) {
                                  /*
                                          here you have access to:
          
                                          package_name, - the app package name
                                          status - success (true) of the request or not (false)
                                          author - the app author
                                          app_name - the app name on the store
                                          locale - the locale defined by default for the app
                                          publish_date - the date when the update was published
                                          version - the version on the store
                                          last_version_description - the update text description
                                       */
                                  try{
                                      if(response != null && response.has("status") && response.getBoolean("status") && response.has("version")){
                                          Toast.makeText(getApplicationContext(), response.getString("version").toString(), Toast.LENGTH_LONG).show();
                                      }
                                      else{
                                          //TODO handling error
                                      }
                                  }
                                  catch (Exception e){
                                      //TODO handling error
                                  }
          
                              }
                          }, new Response.ErrorListener() {
                              @Override
                              public void onErrorResponse(VolleyError error) {
                                  //TODO handling error
                              }
                  });
          

          【讨论】:

          【解决方案13】:

          最简单的方法是使用来自 google 的 firebase 包并使用远程通知或实时配置新版本并将 id 发送给版本号以下的用户 查看更多https://firebase.google.com/

          【讨论】:

            【解决方案14】:

            这里的好处是您可以检查版本号而不是名称,这应该更方便:) 另一方面 - 您应该注意每次发布后更新 api/firebase 中的版本。

            • 从 google play 网页获取版本。我已经实现了这种方式,它的工作时间超过 1 年,但在此期间我必须更改 'matcher' 3-4 次,因为网页上的内容已更改。时不时检查一下也很头疼,因为你不知道在哪里可以更改。 但是如果你还想用这种方式,这里是我基于okHttp的kotlin代码:

              private fun getVersion(onChecked: OnChecked, packageName: String) {
              
              Thread {
                  try {
                      val httpGet = HttpGet("https://play.google.com/store/apps/details?id="
                              + packageName + "&hl=it")
              
                      val response: HttpResponse
                      val httpParameters = BasicHttpParams()
                      HttpConnectionParams.setConnectionTimeout(httpParameters, 10000)
                      HttpConnectionParams.setSoTimeout(httpParameters, 10000)
                      val httpclient = DefaultHttpClient(httpParameters)
                      response = httpclient.execute(httpGet)
              
                      val entity = response.entity
                      val `is`: InputStream
                      `is` = entity.content
                      val reader: BufferedReader
                      reader = BufferedReader(InputStreamReader(`is`, "iso-8859-1"), 8)
                      val sb = StringBuilder()
                      var line: String? = null
                      while ({ line = reader.readLine(); line }() != null) {
                          sb.append(line).append("\n")
                      }
              
                      val resString = sb.toString()
                      var index = resString.indexOf(MATCHER)
                      index += MATCHER.length
                      val ver = resString.substring(index, index + 6) //6 is version length
                      `is`.close()
                      onChecked.versionUpdated(ver)
                      return@Thread
                  } catch (ignore: Error) {
                  } catch (ignore: Exception) {
                  }
              
                  onChecked.versionUpdated(null)
              }.start()
              }
              

            【讨论】:

              【解决方案15】:

              我的解决方法是解析 Google Play 网站并提取版本号。 如果您遇到 CORS 问题或想节省用户设备上的带宽,请考虑从您的网络服务器运行它。

              let ss = [html];
              
              for (let p of ['div', 'span', '>', '<']) {
                let acc = [];
                ss.forEach(s => s.split(p).forEach(s => acc.push(s)));
                ss = acc;
              }
              
              ss = ss
                .map(s => s.trim())
                .filter(s => {
                  return parseFloat(s) == +s;
                });
              
              console.log(ss); // print something like [ '1.10' ]
              

              您可以通过获取https://play.google.com/store/apps/details?id=your.package.name 来获取html 文本。为了可比性,您可以使用https://www.npmjs.com/package/cross-fetch,它适用于浏览器和 node.js。

              其他人提到使用某些 css 类或模式(如“当前版本”)解析来自 Google Play 网站的 html,但这些方法可能不那么健壮。因为谷歌可以随时更改班级名称。它还可以根据用户的区域设置返回不同语言的文本,因此您可能不会得到“当前版本”这个词。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2012-12-30
                • 2022-07-19
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-03-07
                相关资源
                最近更新 更多