How to get a category for each application on an Android device?

I have an Android application that scans all applications installed on the device and then reports this to the server (this is an MDM agent). Any suggestions on how to get the app category? Each has its own list of categories, but basically something like Game, Entertainment, Tools / Utilities, etc.

From what I can say, nothing is related to the category stored on the device itself. I was thinking about using the Android Android API to search for an application in the market and use the category value returned by the search. Not sure how successful a match search will be. Any suggestions on how best to do this?

Any suggestions for a different approach?

Thanks in advance. microphone

+6
source share
6 answers

Any suggestions on how to get the app category?

Applications have no categories. Some markets have categories.

From what I can say, nothing is related to the category stored on the device itself.

Right.

I thought to use the Android Android API to search for an application in the market and use the Category value returned by the search.

There is currently no “Android Android API” unless you have a good legal team and a significant legal protection fund.

In addition, not all applications are distributed through the “Android market”, especially on devices such as the Kindle Fire. In addition, developers can change categories whenever they want, at least in the Google Play Store.

Any suggestions on how best to do this?

Drop this function and go on to other ways to add a value.

+5
source

if you get its package name for each application, you can ask directly to play in the store, which category the application belongs to, parsing the html response page with this library:

org.jsoup.jsoup1.8.3

Here is a snippet to solve your problem:

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; } } } } } 

You can make these requests in AsyncTask or in a service. Hope you find this helpful.

+4
source

You can use AsyncTask below to retrieve the category of Android applications from the playStore using the application package identifier.

 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; } } 

A jsoup library is required to parse an html page. You can find it here org.jsoup.jsoup1.11.1

0
source

I made a Kotlin solution based on @Ankit Kumar Singh answer.
This solution displays the category in enum if you want to do something other than just show it.

 import kotlinx.coroutines.experimental.android.UI import kotlinx.coroutines.experimental.launch import net.nrask.appsanywhere.deviceSettings.installedApps.database.AppCategory import org.jsoup.Jsoup object GetAppCategoryService { private const val APP_URL = "https://play.google.com/store/apps/details?id=" private const val CAT_SIZE = 9 private const val CATEGORY_STRING = "category/" private const val CATEGORY_GAME_STRING = "GAME_" // All games start with this prefix private const val DEFAULT_VALUE = "OTHERS" fun fetchCategory(packageName: String, onResult: (AppCategory) -> Unit) { val url = "$APP_URL$packageName&hl=en" //https://play.google.com/store/apps/details?id=com.example.app&hl=en val categoryRaw = parseAndExtractCategory(url) launch(UI) { onResult(AppCategory.fromCategoryName(categoryRaw ?: DEFAULT_VALUE)) } } private fun parseAndExtractCategory(url: String): String? { return try { val text = Jsoup.connect(url).get()?.select("a[itemprop=genre]") ?: return null val href = text.attr("abs:href") if (href != null && href.length > 4 && href.contains(CATEGORY_STRING)) { getCategoryTypeByHref(href) } else { null } } catch (e: kotlin.Exception) { //TODO handle error null } } private fun getCategoryTypeByHref(href: String): String? { val appCategoryType = href.substring(href.indexOf(CATEGORY_STRING) + CAT_SIZE, href.length) return if (appCategoryType.contains(CATEGORY_GAME_STRING)) { AppCategory.GENERAL_GAMES_CATEGORY_NAME } else appCategoryType } } 

And here is an enumeration with all possible values ​​at a given point in time:

 // Int value is equal to the category name hashvalue - For easy parsing enum class AppCategory(val rawValue: Int) { OTHER(0), ART_AND_DESIGN(1798113474), AUTO_AND_VEHICLES(-201031457), BEAUTY(1955267708), BOOKS_AND_REFERENCE(652448174), BUSINESS(-364204096), COMICS(1993477496), COMMUNICATION(2080958390), DATING(2009386219), EDUCATION(-1799129208), ENTERTAINMENT(-678717592), EVENTS(2056967449), FINANCE(-135275590), FOOD_AND_DRINK(-267698865), HEALTH_AND_FITNESS(704829917), HOUSE_AND_HOME(-908401466), LIBRARIES_AND_DEMO(-1893543311), LIFESTYLE(-1796047851), MAPS_AND_NAVIGATION(1381037124), MEDICAL(1658758769), MUSIC_AND_AUDIO(702385524), NEWS_AND_MAGAZINES(1916976715), PARENTING(561964760), PERSONALIZATION(1779216900), PHOTOGRAPHY(-470332035), PRODUCTIVITY(-953829166), SHOPPING(438165864), SOCIAL(-1843721363), SPORTS(-1842431105), TOOLS(80007611), TRAVEL_AND_LOCAL(856995806), VIDEO_PLAYERS(289768878), WEATHER(1941423060), GAMES("GAMES".hashCode()); companion object { private val map = AppCategory.values().associateBy(AppCategory::rawValue) const val GENERAL_GAMES_CATEGORY_NAME = "GAMES" fun fromCategoryName(name: String): AppCategory { return map[name.hashCode()] ?: AppCategory.OTHER } } } 
0
source

Maybe a little late, but the problem is still there. The OP has the advantage of sending these results to the API (here I assume the API is managed by the OP or its API peers at least).

So, for those who have a similar problem, I would suggest the following:

  1. Collect all the package names that interest you from your device.
  2. Send this data to your API
  3. The API should extract the package names and try to read the results from its cache / database ...
  4. For those packages that do not exist in cache / db, call the "market API" and extract the category - save it in db / cache for reuse in this iteration.
  5. When all requests (cache / dB and market API) are complete, do whatever you want with the results.

What to consider:

When several users try to request the same package name from your API, and you do not have a category for this package in your / db cache ... Make 1 request to the "market API" for packagex and update packagex in your / db cache in "wait for results" state - the next request should receive either "wait for results" or the result returned by the "market API".

You should also consider abandoning possible “market APIs” (the market API does not work, not the Google Play application or something like that). This decision is mainly related to your domain, and the business trend that you are trying to catch will force you to make a decision about it. If you really want to deal with things of this category, you can roll back this fallback to a human solution and update your db / cache API for packagex .

create a good API that would elegantly handle these and similar scenarios, then you could even commercialize it to a certain extent and the "end point of the market API" - the AKA play store package details page. This page would lose most of the fake users :)

0
source

I also ran into the same problem. The solution for the above request is indicated below.

First, download the Jsoup library or download the jar file.

or add this to your build.gradle implementation (Module: app) 'org.jsoup: jsoup: 1.11.3'

The private class FetchCategoryTask extends AsyncTask {

 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 = "https://play.google.com/store/apps/details?id=com.imo.android.imoim"; //GOOGLE_URL + packageInfo.packageName; Log.i(TAG, query_url); category = getCategory(query_url); Log.e("CATEGORY", category); // store category or do something else //} return null; } private String getCategory(String query_url) { try { Document doc = Jsoup.connect(query_url).get(); Elements link = doc.select("a[class=\"hrTbp R8zArc\"]"); return link.text(); } catch (Exception e) { Log.e("DOc", e.toString()); } } 

} In return, you will receive the application company name and application category

0
source

Source: https://habr.com/ru/post/981976/


All Articles