Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: getting an APKs minSdkVersion from Android code [duplicate]

I'm developing an Android app that has the ability of installing additional apps (which act as plugins for my app) if the user requires it.

However, each of these additional apps may require a specific Android version to run. I would like to perform a check at runtime to see if the APK I'm trying to install is actually compatible with the device.

Now, with the following method:

public PackageManager getPackageArchiveInfo(String archiveFilePath, int flags)

I can get info on an APK file. However, the problem is that the returned information seems to only include the APK's targetSdkVersion but not the minSdkVersion, which to my understanding is the one that actually determines the minimum version of Android an app can be installed/run on. The targetSdkVersion if I understand correctly is just the "optimal" version.

So, long story short, how can I determine whether an APK cna run on the device from Android itself? (I know I can use AAPT on desktop, but that is not available on Android itself)

like image 760
Master_T Avatar asked May 26 '15 10:05

Master_T


1 Answers

You can do it.

For Android N and above, use the official API.

For earlier versions, you can use this code, which is very efficient and fast. Here's a bit better version of it (works even if getAttributeName returns an empty string) :

public static int getMinSdkVersion(File apkFile) throws ClassNotFoundException, IllegalAccessException, InstantiationException,
        NoSuchMethodException, InvocationTargetException, IOException, XmlPullParserException {
    final Class assetManagerClass = Class.forName("android.content.res.AssetManager");
    final AssetManager assetManager = (AssetManager) assetManagerClass.newInstance();
    final Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
    final int cookie = (Integer) addAssetPath.invoke(assetManager, apkFile.getAbsolutePath());
    final XmlResourceParser parser = assetManager.openXmlResourceParser(cookie, "AndroidManifest.xml");
    while (parser.next() != XmlPullParser.END_DOCUMENT)
        if (parser.getEventType() == XmlPullParser.START_TAG && parser.getName().equals("uses-sdk"))
            for (int i = 0; i < parser.getAttributeCount(); ++i)
                if (parser.getAttributeNameResource(i) == android.R.attr.minSdkVersion)//alternative, which works most of the times: "minSdkVersion".equals(parser.getAttributeName(i)))
                    return parser.getAttributeIntValue(i, -1);
    return -1;
}

And, if you want an all around solution (which sadly can take a lot of heap memory and time), you can use an APK parsing library, such as APKParser. If you want just the basics of it, consider the APKParser improvement I suggested here.

like image 137
android developer Avatar answered Sep 29 '22 14:09

android developer