9
votes

Comment obtenir une catégorie pour chaque application sur le périphérique sur Android?

J'ai une application Android qui analyse pour toutes les applications installées sur l'appareil, puis signale ceci à un serveur (c'est un agent MDM). Toute suggestion sur la manière d'obtenir la catégorie de l'application? Tout le monde a une liste différente de catégories, mais essentiellement quelque chose comme jeu, divertissement, outils / utilitaires, etc.

De ce que je peux dire, il n'y a rien de lié à la catégorie stockée sur l'appareil lui-même. J'y envisagé d'utiliser l'API du marché Android pour rechercher l'application sur le marché et utiliser la valeur de catégorie renvoyée par la recherche. Je ne sais pas comment réussir cela trouvera une correspondance. Toute suggestion sur la meilleure façon de faire cela?

Toute suggestion sur une approche différente?

Merci d'avance. Mike


1 commentaires

Je pense que je le ferais. J'ai utilisé l'API «Market» Android (non officiel) et, à mon avis, son très développeur convivial et fiable. La meilleure façon de rechercher est de rechercher un nom de package et vous pouvez obtenir la catégorie en retour. Je ne peux pas penser à une autre façon, car dans l'application elle-même, il ne définit que Wheater, c'est un jeu ou une application de budget, etc. Si bonne chance avec ça!


7 Réponses :


6
votes

Toute suggestion sur la façon d'obtenir la catégorie de l'application?

Les applications n'ont pas de catégories. Certains marchés ont des catégories.

De ce que je peux dire, il n'y a rien de lié à la catégorie stockée sur l'appareil lui-même.

correct.

Je pensais utiliser l'API du marché Android pour rechercher l'application sur le marché et utiliser la valeur de catégorie renvoyée par la recherche.

À l'heure actuelle, il n'y a pas d'API "Android Market", à moins que vous n'ayez une bonne équipe juridique et un fonds de défense juridique important.

En outre, toutes les applications ne sont pas distribuées via le "marché Android", en particulier sur des périphériques comme le Kindle Fire. En outre, les développeurs sont invités à changer de catégories chaque fois qu'ils le souhaitent, du moins sur le magasin Google Play.

Toute suggestion sur la meilleure façon de faire cela?

Déposez la fonctionnalité et passez à d'autres moyens d'ajouter de la valeur.


1 commentaires

Hey Dr. Booster faire cela. Ils ont classé tous les jeux et montrent à la grille. Netty Master a également la même chose que vous ayez une idée de la façon dont ils l'ont fait et une chose que j'étais sur Internet, mais elles ont fait la même chose qui signifie qu'ils font quelque chose qui ne nécessite aucune API ou aucune API



8
votes

Si vous obtenez pour chaque application Son nom de package, vous pouvez demander directement à lire Store Quelle catégorie d'une application appartient à une application HTML avec cette bibliothèque:

org.jsoup.jsoup1.8.3 p>

Voici un extrait pour résoudre votre problème: P>

public class MainActivity extends AppCompatActivity {

public final static String GOOGLE_URL = "https://play.google.com/store/apps/details?id=";
public static final String ERROR = "error";

...


   private class FetchCategoryTask extends AsyncTask<Void, Void, Void> {

       private final String TAG = FetchCategoryTask.class.getSimpleName();
       private PackageManager pm;
       private ActivityUtil mActivityUtil;

       @Override
       protected Void doInBackground(Void... errors) {
          String category;
           pm = getPackageManager();
           List<ApplicationInfo> packages = pm.getInstalledApplications(PackageManager.GET_META_DATA);
           Iterator<ApplicationInfo> iterator = packages.iterator();
           while (iterator.hasNext()) {
               ApplicationInfo packageInfo = iterator.next();
               String query_url = GOOGLE_URL + packageInfo.packageName;
               Log.i(TAG, query_url);
               category = getCategory(query_url);
               // store category or do something else
           }
           return null;
        }


        private String getCategory(String query_url) {
           boolean network = mActivityUtil.isNetworkAvailable();
           if (!network) {
               //manage connectivity lost
               return ERROR;
           } else {
               try {
                   Document doc = Jsoup.connect(query_url).get();
                   Element link = doc.select("span[itemprop=genre]").first();
                   return link.text();
               } catch (Exception e) {
                   return ERROR;
               }
           }
        }
    }  
}


3 commentaires

Hé, ça marche bien, mais si Google Play est dans une autre langue? Comment obtenir uniquement la version anglaise de la catégorie?


Essayez d'ajouter "&& hl = fr" à Query_url;)


J'ai essayé ce code et cela renvoie toujours une erreur. Y a-t-il quelque chose que je veux faire de ce code?



0
votes

Vous pouvez utiliser ci-dessous asynctack pour extraire la catégorie d'applications Android à partir de PlayStore à l'aide de l'ID de package d'application.

import android.content.Context;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.util.Log;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;

public class GetAppCategory extends AsyncTask<String, Void, String> {

    //Main URL for each app on Play Store
    public static final String APP_URL = "https://play.google.com/store/apps/details?id=";

    //Use below String if extracting 'CATEGORY' from href tag.
    private final String CATEGORY_STRING = "category/";

    private final int cat_size = 9;

    /*Use below String for identified 'GAME' apps, which must start with this prefix.
    Here I only display 'Games' as category for all Games app instead of showing their subCategory also*/
    private final String CATEGORY_GAME_STRING = "GAME_";

    //Name of the app package for which you want to get category.
    private String packageName = null;

    private PackageManager pm = null;

    //Activity or Application context as per requirement.
    private Context appContext;

    /* You can add default system app OR non play store app package name here as comma seprated for ignore them
     and set their category directly 'Others' OR anythings you wish. */
    private final String extractionApps = "com.android.providers.downloads.ui, com.android.contacts," +
            " com.android.gallery3d, com.android.vending, com.android.calculator2, com.android.calculator," +
            " com.android.deskclock, com.android.messaging, com.android.settings, com.android.stk";

    //Class level TAG, use for Logging.
    private final String TAG = "GetAppCategory";

    /**
     * @param packageName: package name of the app, you want to extract category.
     * @param appContext:  Activity/Application level Context ap per requirement.
     */
    public GetAppCategory(String packageName, Context appContext) {
        this.packageName = packageName;
        this.appContext = appContext;
    }

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

            pm = appContext.getPackageManager();

            if (packageName != null && packageName.length() > 1) {

                if (packageName.contains("package:")) {
                    packageName = packageName.replace("package:", "");
                }
                /**
                 * Mathod used for parse play store html page and extract category from their.
                 */
                String appCategoryType = parseAndExtractCategory(packageName);

                Log.i(TAG, "package :" + packageName);
                Log.i(TAG, "APP_CATEGORY: " + appCategoryType);
            }

        } catch (Exception e) {
            //TODO:: Handle Exception
            e.printStackTrace();
        } finally {
            //TODO::
        }
        return null;
    }

    @Override
    protected void onPostExecute(String result) {

    }


    /**
     * @param packageName
     * @return
     */

    private String parseAndExtractCategory(String packageName) {

        //You can pass hl={language_code} for get category in some other langauage also other than English.
        //String url = APP_URL + packageName + "&hl=" + appContext.getString(R.string.app_lang);

        String url = APP_URL + packageName + "&hl=en"; //{https://play.google.com/store/apps/details?id=com.example.app&hl=en}
        String appCategoryType = null;
        String appName = null;

        try {

            if (!extractionApps.contains(packageName)) {
                Document doc = null;
                try {
                    doc = Jsoup.connect(url).get();

                    if (doc != null) {

                        //TODO: START_METHOD_1
                        //Extract category String from a <anchor> tag value directly.
                        //NOTE: its return sub category text, for apps with multiple sub category.
                        //Comment this method {METHOD_1}, if you wish to extract category by href value.
                        Element CATEGORY_SUB_CATEGORY = doc.select("a[itemprop=genre]").first();
                        if (CATEGORY_SUB_CATEGORY != null) {
                            appCategoryType = CATEGORY_SUB_CATEGORY.text();
                        }
                        //TODO: END_METHOD_1

                        //TODO: START_METHOD_2
                        // Use below code only if you wist to extract category by href value.
                        //Its return parent or Main Category Text for all app.
                        //Comment this method {METHOD_2}, If you wihs to extract category from a<anchor> value.
                        if (appCategoryType == null || appCategoryType.length() < 1) {
                            Elements text = doc.select("a[itemprop=genre]");

                            if (text != null) {
                                if (appCategoryType == null || appCategoryType.length() < 2) {
                                    String href = text.attr("abs:href");
                                    if (href != null && href.length() > 4 && href.contains(CATEGORY_STRING)) {
                                        appCategoryType = getCategoryTypeByHref(href);
                                    }
                                }
                            }
                        }
                        //TODO: END_METHOD_2

                        if (appCategoryType != null && appCategoryType.length() > 1) {
                            /**
                             * Ger formatted category String by removing special character.
                             */
                            appCategoryType = replaceSpecialCharacter(appCategoryType);
                        }

                    }
                } catch (IOException e) {
                    //appCategoryType = appContext.getString(R.string.category_others);
                    appCategoryType = "OTHERS";
                    //TODO:: Handle Exception
                    e.printStackTrace();
                }
            } else {
                //appCategoryType = appContext.getString(R.string.category_others);
                appCategoryType = "OTHERS";
            }
        } catch (Exception e) {
            //TODO:: Handle Exception
            e.printStackTrace();
        }
        return appCategoryType;
    }

    /**
     * @param href
     * @return
     */
    private String getCategoryTypeByHref(String href) {
        String appCategoryType = null;
        try {
            appCategoryType = href.substring((href.indexOf(CATEGORY_STRING) + cat_size), href.length());
            if (appCategoryType != null && appCategoryType.length() > 1) {
                if (appCategoryType.contains(CATEGORY_GAME_STRING)) {
                    //appCategoryType = appContext.getString(R.string.games);
                    appCategoryType = "GAMES";
                }
            }
        } catch (Exception e) {
            //TODO:: Handle Exception
            e.printStackTrace();
        }
        return appCategoryType;
    }

    /**
     * @param appCategoryType
     * @return: formatted String
     */
    private String replaceSpecialCharacter(String appCategoryType) {
        try {
            //Find and Replace '&amp;' with '&' in category Text
            if (appCategoryType.contains("&amp;")) {
                appCategoryType = appCategoryType.replace("&amp;", " & ");
            }

            //Find and Replace '_AND_' with ' & ' in category Text
            if (appCategoryType.contains("_AND_")) {
                appCategoryType = appCategoryType.replace("_AND_", " & ");
            }

            //Find and Replace '_' with ' ' <space> in category Text
            if (appCategoryType.contains("_")) {
                appCategoryType = appCategoryType.replace("_", " ");
            }
        } catch (Exception e) {
            //TODO:: Handle Exception
            e.printStackTrace();
        }
        return appCategoryType;
    }
}


0 commentaires

3
votes

J'ai fait une solution de kotlin basée sur la réponse de @ankit Kumar Singh.
Cette solution plante la catégorie à un énumé, au cas où vous voudriez faire d'autres choses que de simplement le montrer.

// Note: Enum name matches API value and should not be changed
enum class AppCategory {
    OTHER,
    ART_AND_DESIGN,
    AUTO_AND_VEHICLES,
    BEAUTY,
    BOOKS_AND_REFERENCE,
    BUSINESS,
    COMICS,
    COMMUNICATION,
    DATING,
    EDUCATION,
    ENTERTAINMENT,
    EVENTS,
    FINANCE,
    FOOD_AND_DRINK,
    HEALTH_AND_FITNESS,
    HOUSE_AND_HOME,
    LIBRARIES_AND_DEMO,
    LIFESTYLE,
    MAPS_AND_NAVIGATION,
    MEDICAL,
    MUSIC_AND_AUDIO,
    NEWS_AND_MAGAZINES,
    PARENTING,
    PERSONALIZATION,
    PHOTOGRAPHY,
    PRODUCTIVITY,
    SHOPPING,
    SOCIAL,
    SPORTS,
    TOOLS,
    TRAVEL_AND_LOCAL,
    VIDEO_PLAYERS,
    WEATHER,
    GAMES;

    companion object {
        private val map = values().associateBy(AppCategory::name)
        private const val CATEGORY_GAME_STRING = "GAME_" // All games start with this prefix

        fun fromCategoryName(name: String): AppCategory {
            if (name.contains(CATEGORY_GAME_STRING)) return GAMES
            return map[name.toUpperCase(Locale.ROOT)] ?: OTHER
        }
    }
}


0 commentaires

0
votes

Probablement un peu en retard, mais le problème est toujours là. L'OP a l'avantage en raison de l'envoi de ces résultats à l'API (ici, je suppose que l'API est gérée par l'OP ou ses collègues de l'API au moins).

Donc, pour toute personne ayant le problème similaire, je suggère de suivre:

  1. Collectez tous les noms de packages qui vous intéressent à partir du périphérique.
  2. Envoyez ces données à la votre API
  3. API doit extraire les noms de paquets et essayer de lire les résultats de son cache / dB ...
  4. Pour ces packages qui n'existent pas dans le cache / dB constituent une catégorie "API de marché" - enregistrez-la sur la DB / Cache pour la réutilisation de cette itération.
  5. Lorsque toutes les demandes (au cache / dB et à l'API du marché) sont terminées, faites tout ce que vous voulez avec les résultats.

    choses à considérer:

    Lorsque plusieurs utilisateurs tentent d'interroger votre API pour un même nom de package et que vous n'avez pas de catégorie pour ce package dans votre cache / dB ... Faire 1 demande à "API de marché" pour packagex et mettre à jour packagex dans votre cache / dB sur "En attente de résultats" State - Suivant Demande devrait soit obtenir un "En attente de résultats "ou un résultat que" API de marché "est retourné.

    On devrait également envisager une relèvement sur une éventuelle "API de marché" (API de marché ne fonctionne pas, pas une application Google Play, ou quelque chose de similaire). Cette décision est fondamentalement liée à votre domaine et à la tendance des affaires que vous essayez d'attraper forcera une décision à ce sujet pour vous. Si vous êtes vraiment dans l'obtention de cette catégorie, les trucs ont été triés, vous pouvez pipeline cette cassette à la décision humaine et mettre à jour votre API dB / cache pour packagex en conséquence.

    Mettez une API agréable qui manipulerait ces scénarios et des scénarios similaires gracieusement, on pourrait probablement même la commercialiser dans une certaine mesure et une certaine page de fin d'accès à l'API de marché. Cette page perdrait une grande partie de ses faux utilisateurs :)


0 commentaires

4
votes

J'ai également fait face au même problème. La solution pour la requête ci-dessus est indiquée ci-dessus.

Premièrement, téléchargez la bibliothèque jsoup ou téléchargez le fichier jar.

ou Ajouter ceci à votre build.gradle (Module: app) implémentation 'org.jsoup: jsoup: 1.11.3' xxx

En retour, vous obtiendrez le nom de la société d'application et la catégorie de l'application


3 commentaires

De la solution ci-dessus, j'ai eu le nom de la société et le nom de la catégorie, mais est-il possible de trouver son jeu ou une application?


@Makvin Oui, vous pouvez déterminer s'il s'agit d'un jeu ou d'une application. Les jeux ont également une sous-catégorie énumérer la liste (par exemple, action, aventure, arcade, etc.). Si ma catégorie d'application est identique à l'action ou à l'aventure ou à l'arcade, je l'assignerai comme un jeu, c'est un travail autour, mais cela pourrait vous aider à découvrir si l'application est un jeu ou non Thagank


Cela fonctionnera-t-il même aujourd'hui? Sera-t-il toujours en anglais? Y a-t-il un moyen d'obtenir toutes les catégories possibles? Au cas où les choses changent, comment avez-vous trouvé quoi mettre en tant que paramètre pour doc.select () ?



6
votes

Je sais que c'est un ancien poste, mais pour toute personne recherchée, le niveau 26 de l'API 26 (O) a ajouté des catégories à android.content.pm.applicationinfo .

de la docs https://developer.android.com/reference / Android / Contenu / PM / ApplicationInfo # Catégorie :

Public int Catégorie

La catégorie de cette application. Les catégories sont utilisées pour en grappes plusieurs applications dans des groupes significatifs, tels que la résumé de la batterie, du réseau ou du disque. Les applications ne doivent définir cette valeur que lorsqu'elles s'intègrent bien dans l'une des catégories spécifiques.

Ensemble de r.attr.appCategory attribut dans le manifeste . Si le manifeste ne définit pas une catégorie, cette valeur a peut-être été fournie par l'installateur via Packagemanager # SetApplicationCategoryHint (chaîne, int) . La valeur est catégorie_undefinefind , catégorie_game , Catégorie_audio , catégorie_video , catégorie_image , Catégorie_social , catégorie_news , catégorie_maps ou catégorie_productivité

On peut maintenant faire quelque chose comme: xxx


0 commentaires