How can i get the apk file name and path programmatically? - android

I want to get the exact file name of a program if I already know the package name of the target apk. For instance, if I know the package name of my apk, which is com.packagename, how can I get the exact path and file name of that package? Btw, i don't want to get just MY apk location, i want the location of any package name i apply. SystemTuner pro is able to do this so i know it is possible, just not sure how.
Thanks guys!

/**
* Get the apk path of this application.
* #param context any context (e.g. an Activity or a Service)
* #return full apk file path, or null if an exception happened (it should not happen)
*/
public static String getApkName(Context context) {
String packageName = context.getPackageName();
PackageManager pm = context.getPackageManager();
try {
ApplicationInfo ai = pm.getApplicationInfo(packageName, 0);
String apk = ai.publicSourceDir;
return apk;
} catch (Throwable x) {
}
return null;
}
EDIT
In defense of catch (Throwable x) in this case. At first, now it is well-known that Checked Exceptions are Evil. At second, you cannot predict what may happen in future versions of Android. There already is a trend to wrap checked exceptions into runtime exceptions and re-throw them. (And a trend to do silly things that were unthinkable in the past.) As to the children of Error, well, if the package manager cannot find the apk that is running, it is the kind of problems for which Errors are thrown. Probably the last lines could be
} catch (Throwable x) {
return null;
}
but I do not change working code without testing it.

PackageManager.getPackageInfo() returns information about the package, and PackageInfo.applicationInfo field has required information about the application.

Well, i would like to mark Yuri as the answer but i already knew about that stuff. So I went through each and every option from PackageManager.ApplicationInfo and found .publicSourceDir
So a complete answer with code to my question would be
PackageManager pm = getPackageManager();
try {
ApplicationInfo ai = pInfo.getApplicationInfo(<packageName here>, 0);
String sourceApk = ai.publicSourceDir;
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
So thanks again guys, got my brain goin once again Love StackOverflow!

in above answer need change pInfo to pm
like this
PackageManager pm = getPackageManager();
try {
ApplicationInfo ai = pm.getApplicationInfo(<packageName here>, 0);
String sourceApk = ai.publicSourceDir;
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this answer by Seth

Related

How to get package name from apk in Android?

I am developing an app which will contain a list of Apps. On click the user will be redirected to the Play Store to download this app. On successful download I have to send that apps package name to a server to validate it. How can I do that?
I assume you want to do this at runtime, so your app can read its own package_id w/o having this hardcoded. For that you need to use PackageManager's getPackageInfo() method:
protected String getPackageName() {
try {
PackageInfo packageInfo = getPackageManager.getPackageInfo(getPackageName(), 0);
return packageInfo.applicationInfo.packageName;
} catch (Exception e) {
e.printStacktrace();
}
return null;
}
Use apkanalyzer, its part of the Android studio:
apkanalyzer manifest application-id path/to/apk/file.apk

DexClassLoader, reload Code fails with Signal 7

I'm trying to build a plugin-System, where DexClassLoader is fetching code from other installed apks containing fragments(my plugins), and showing them in my host. This is working quite nice.
I also like to make the plugins hotswappable, this means I can change the code from a plugin, install it new and the host will notice and will load the new code. This also works, if I'm changing the code for the first time. (Although I thought it shouldn't, it seems I've got a wrong understanding of this code:
try {
requiredClass = Class.forName(fullName);
} catch(ClassNotFoundException e) {
isLoaded = false;
}
)
If i'm trying it a second time with the same plugin, the host shuts down at requiredClass = classLoader.loadClass(fullName); with something like
libc Fatal signal 7 (SIGBUS) at 0x596ed4d6 (code=2), thread 28814
(ctivityapp.host)
Does anybody has a deeper insight in the functionality of DexClassLoader and may tell me, what is happening here? I'm quite stuck at this.
Heres the full code of the method loading the foreign code:
/**
* takes the name of a package as String, and tries to load the code from the corresponding akp using DexclassLaoder.
* Checking if a package is a valid plugin must be done before calling this.
* The Plugin must contain a public class UI that extends Fragment and implements plugin as a starting point for loading
* #param packageName The full name of the package, as String
* #return the plugins object if loaded, null otherwise
*/
private Plugin attachPluginToHost(String packageName) {
try {
Class<?> requiredClass = null;
final ApplicationInfo info = context.getPackageManager().getApplicationInfo(packageName,0);
final String apkPath = info.sourceDir;
final File dexTemp = context.getDir("temp_folder", 0);
final String fullName = packageName + ".UI";
boolean isLoaded = true;
// Check if class loaded
try {
requiredClass = Class.forName(fullName);
} catch(ClassNotFoundException e) {
isLoaded = false;
}
if (!isLoaded) {
final DexClassLoader classLoader = new DexClassLoader(apkPath, dexTemp.getAbsolutePath(), null, context.getApplicationContext().getClassLoader());
requiredClass = classLoader.loadClass(fullName);
}
if (null != requiredClass) {
// Try to cast to required interface to ensure that it's can be cast
final Plugin plugin = Plugin.class.cast(requiredClass.newInstance());
installedPlugins.put(plugin.getName(), plugin);
return plugin;
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
Many thanks in advance!
Not that it really matters (As nobody is actually viewing this), or that I even understand what's going on, but deleting the corresponding file of the plugin in dexTemp.getAbsolutePath() before reloading it solves the problem.
PS: Tumbleweed-Badge, YAY!

Get Application Directory

Does someone know how do I get the path of my application directory? (e.g. /data/data/my.app.lication/)
Currently I'm using this method: myActivity.getFilesDir().getParent(); but it seems to me like a workaround when there's a simpler solution. Also, the side-effect is the creation of the files directory, which is un-needed.
Clarification: First - Thanks for the repliers. I try to understand if there's already exists method that does it, not for another work-around.
There is a simpler way to get the application data directory with min API 4+. From any Context (e.g. Activity, Application):
getApplicationInfo().dataDir
http://developer.android.com/reference/android/content/Context.html#getApplicationInfo()
PackageManager m = getPackageManager();
String s = getPackageName();
PackageInfo p = m.getPackageInfo(s, 0);
s = p.applicationInfo.dataDir;
If eclipse worries about an uncaught NameNotFoundException, you can use:
PackageManager m = getPackageManager();
String s = getPackageName();
try {
PackageInfo p = m.getPackageInfo(s, 0);
s = p.applicationInfo.dataDir;
} catch (PackageManager.NameNotFoundException e) {
Log.w("yourtag", "Error Package name not found ", e);
}
Just use this in your code
context.getApplicationInfo().dataDir
I got this
String appPath = App.getApp().getApplicationContext().getFilesDir().getAbsolutePath();
from here:
For current Android application package:
public String getDataDir(Context context) throws Exception {
return context.getPackageManager().getPackageInfo(context.getPackageName(), 0).applicationInfo.dataDir;
}
For any package:
public String getAnyDataDir(Context context, String packageName) throws Exception {
return context.getPackageManager().getPackageInfo(packageName, 0).applicationInfo.dataDir;
}
If you're trying to get access to a file, try the openFileOutput() and openFileInput() methods as described here. They automatically open input/output streams to the specified file in internal memory. This allows you to bypass the directory and File objects altogether which is a pretty clean solution.
Based on #jared-burrows' solution. For any package, but passing Context as parameter...
public static String getDataDir(Context context) throws Exception {
return context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0)
.applicationInfo.dataDir;
}

How do I get the version number of an application in Android?

We have a set of 3-5 android applications that we have developed for an enterprise to integrate with our back-end. How do we create an installer system that upgrades applications automatically. We were thinking of getting version numbers and querying the backend to get current versions and downloading them.
How do I get the version number of an application in Android?
ApplicationInfo info = getApplicationInfo();
try {
info = getPackageManager().getApplicationInfo(info.packageName, PackageManager.GET_META_DATA);
} catch (NameNotFoundException e) {
e.printStackTrace();
}
Any pointers will be most useful.
Thanks
Sameer
Using the function below you can get the current Version Name or No for the application.
This you can check against that of the app at server side and if needed you can upgrade app.
public static function String getVersionName(Context context, Class cls) {
try {
ComponentName comp = new ComponentName(context, cls);
PackageInfo pinfo = context.getPackageManager().getPackageInfo(comp.getPackageName(), 0);
return pinfo.versionName;
} catch (android.content.pm.PackageManager.NameNotFoundException e) {
return null;
}
}

Android- Using DexClassLoader to load apk file

I've hit a bit of a wall. Any help would be appreciated. I have an app that I want to use DexClassLoader to load another apk file.
Here is my code:
DexClassLoader dLoader = new DexClassLoader("/sdcard/download/test.apk","/sdcard/download",null,ClassLoader.getSystemClassLoader().getParent());
Class calledClass = dLoader.loadClass("com.test.classname");
Intent it=new Intent(this, calledClass);
it.setClassName("com.test", "com.test.classname");
startActivity(it);
Now I had already installed test.apk so when I ran the above code it
worked fine and launched the application. However I want to be able to
run this without test.apk being installed already (as that would
defeat the entire point of the application) . So I uninstalled it and
when I ran the my app again I get this error:
android.content.ActivityNotFoundException: Unable to find explicit
activity class {com.test/com.test.classname}; have you declared this
activity in your AndroidManifest.xml.
So I'm a bit stumped here. This activity is declared in the Manifest
of the apk I am trying to run. I can't declare it in my applications
Manifest. Any ideas?
Thanks,
Craig
Try using Android's PathClassLoader:
String packagePath = "com.mypackage";
String classPath = "com.mypackage.ExternalClass";
String apkName = null;
try {
apkName = getPackageManager().getApplicationInfo(packagePath,0).sourceDir;
} catch (PackageManager.NameNotFoundException e) {
// catch this
}
// add path to apk that contains classes you wish to load
String extraApkPath = apkName + ":/path/to/extraLib.apk"
PathClassLoader pathClassLoader = new dalvik.system.PathClassLoader(
apkName,
ClassLoader.getSystemClassLoader());
try {
Class<?> handler = Class.forName(classPath, true, pathClassLoader);
} catch (ClassNotFoundException e) {
// catch this
}
Although the question is old, I will answer because I struggled a bit to find a clear answer for your same question for myself. First, I would like to highlight that a clear requirement in your question is to load a class from an .apk that is not already installed on the device. Therefore, calling the package manager using getPackageManager() and providing it with the package path will clearly lead to NameNotFoundException because the .apk that has the package is not installed on the device.
So, the way to go about loading classes from an .apk file that is not installed on the device (i.e. you only have the .apk stored in a directory on your SDCARD) is by using DexClassLoader as follows:
1- Make sure you have the .apk file in a directory on your SDCARD. I've mine Offloadme.apk in the Download folder on my SDCARD.
2- Add read permission in your AndroidManifest.xml to allow your app to read from the manifest.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
3- Use the following definitions to define the path of the .apk, the class name inside the apk, and method name in that class that you would like to invoke:
final String apkFile =Environment.getExternalStorageDirectory().getAbsolutePath()+"/Download/Offloadme.apk";
String className = "com.khaledalanezi.offloadme.SimpleCalculator";
String methodToInvoke = "add";
4- Use the DexClassLoader to load the .apk and call the add method in the SimpleCalculator class using reflection as follows:
final File optimizedDexOutputPath = getDir("outdex", 0);
DexClassLoader dLoader = new DexClassLoader(apkFile,optimizedDexOutputPath.getAbsolutePath(),
null,ClassLoader.getSystemClassLoader().getParent());
try {
Class<?> loadedClass = dLoader.loadClass(className);
Object obj = (Object)loadedClass.newInstance();
int x =5;
int y=6;
Method m = loadedClass.getMethod(methodToInvoke, int.class, int.class);
int z = (Integer) m.invoke(obj, y, x);
System.out.println("The sum of "+x+" and "+"y="+z);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Note that in my simple example, I added two numbers using the add method available in the SimpleCalculator class loaded from the Offloadme.apk file stored on my SDCARD and I was able to print the correct answer which is 11.
You can't do that. Even if you're able to access classes from external file, Android still does not know them. And you don't run activities directly, but by requesting Android to run them, so they have to be registered/installed into system.

Categories

Resources