Need some help by retrieving *.apk file name from Android device programmaticaly ? Could any body provide some Android methods doing that or even shell commands run under Android to get the file location , if I know just a part from file name ?
Also if there is a way how to find out where the *.apk file went after downloading from Market or outside Market ?
Thank you in advance.
List<ApplicationInfo> PackageManager.getInstalledApplications() will give you a list of the installed applications, and ApplicationInfo.sourceDir is the path to the .apk file.
PackageManager pm = getPackageManager();
for (ApplicationInfo app : pm.getInstalledApplications(0)) {
Log.d("PackageList", "package: " + app.packageName + ", sourceDir: " + app.sourceDir);
}
Outputs something like this:
package: com.tmobile.themechooser, sourceDir: /system/app/ThemeChooser.apk
package: com.tmobile.thememanager, sourceDir: /system/app/ThemeManager.apk
package: com.touchtype.swiftkey, sourceDir: /data/app/com.touchtype.swiftkey-1.apk
package: com.twitter.android, sourceDir: /data/app/com.twitter.android-2.apk
package: fm.last.android, sourceDir: /data/app/fm.last.android-1.apk
$ adb shell pm list packages -f
This gave me path in form /data/app/xxx.apk:
https://developer.android.com/reference/android/content/Context.html#getPackageResourcePath%28%29
You can also do adb bugreport and look at the output. You'll want to look for <package name="com.app.package" codePath="path/to/the/app.apk"...
The apps that you download go to /data/app so using ls you can get a list of the downloaded apks.
Related
i'm trying to install flutter on my windows and when i type flutter doctor on cmd i get error then it exit the cmd with no error message , and i try to write flutter doctor on git batch i get this error message
Checking Dart SDK version...
The term 'Unblock-File' is not recognized as the name of a cmdlet, function, sc
ript file, or operable program. Check the spelling of the name, or if a path wa
s included, verify that the path is correct and try again.
At line:1 char:13
+ Unblock-File <<<< -Path 'C:\flutter/bin/internal/update_dart_sdk.ps1'; & 'C:
\flutter/bin/internal/update_dart_sdk.ps1'; exit $LASTEXITCODE;
+ CategoryInfo : ObjectNotFound: (Unblock-File:String) [], Comman
dNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Flutter requires PowerShell 5.0 or newer.
See https://flutter.dev/docs/get-started/install/windows for more.
Current version is 2.
i have made variable name path with this value
C:\Windows\System32;C:\Program Files\Git\git-
cmd.exe;C:\flutter\bin;C:\Windows\System32\WindowsPowerShell\v1.0;C:\Program
Files\Git\bin\git.exe;C:\Program Files\Git\cmd
You will need to install Powershell 5.0. I also recommend you to check the system requirements page for installing flutter.
Background
So far, I was able to install APK files using root (within the app), via this code:
pm install -t -f fullPathToApkFile
and if I want to (try to) install to sd-card :
pm install -t -s fullPathToApkFile
The problem
Recently, not sure from which Android version (issue exists on Android P beta, at least), the above method fails, showing me this message:
avc: denied { read } for scontext=u:r:system_server:s0 tcontext=u:object_r:sdcardfs:s0 tclass=file permissive=0
System server has no access to read file context u:object_r:sdcardfs:s0 (from path /storage/emulated/0/Download/FDroid.apk, context u:r:system_server:s0)
Error: Unable to open file: /storage/emulated/0/Download/FDroid.apk
Consider using a file under /data/local/tmp/
Error: Can't open file: /storage/emulated/0/Download/FDroid.apk
Exception occurred while executing:
java.lang.IllegalArgumentException: Error: Can't open file: /storage/emulated/0/Download/FDroid.apk
at com.android.server.pm.PackageManagerShellCommand.setParamsSize(PackageManagerShellCommand.java:306)
at com.android.server.pm.PackageManagerShellCommand.runInstall(PackageManagerShellCommand.java:884)
at com.android.server.pm.PackageManagerShellCommand.onCommand(PackageManagerShellCommand.java:138)
at android.os.ShellCommand.exec(ShellCommand.java:103)
at com.android.server.pm.PackageManagerService.onShellCommand(PackageManagerService.java:21125)
at android.os.Binder.shellCommand(Binder.java:634)
at android.os.Binder.onTransact(Binder.java:532)
at android.content.pm.IPackageManager$Stub.onTransact(IPackageManager.java:2806)
at com.android.server.pm.PackageManagerService.onTransact(PackageManagerService.java:3841)
at android.os.Binder.execTransact(Binder.java:731)
This seems to also affect popular apps such as "Titanium backup (pro)", which fails to restore apps.
What I've tried
Looking at what's written, it appears it lacks permission to install APK files that are not in /data/local/tmp/.
So I tried the next things, to see if I can overcome it:
set the access to the file (chmod 777) - didn't help.
grant permissions to my app, of both storage and REQUEST_INSTALL_PACKAGES (using ACTION_MANAGE_UNKNOWN_APP_SOURCES Intent) - didn't help.
create a symlink to the file, so that it will be inside the /data/local/tmp/, using official API:
Os.symlink(fullPathToApkFile, symLinkFilePath)
This didn't do anything.
create a symlink using this :
ln -sf $fullPathToApkFile $symLinkFilePath
This partially worked. The file is there, as I can see it in Total Commander app, but when I try to check if it exists there, and when I try to install the APK from there, it fails.
Copy/move (using cp or mv) the file to the /data/local/tmp/ path, and then install from there. This worked, but it has disadvantages: moving is risky because it temporarily hides the original file, and it changes the timestamp of the original file. Copying is bad because of using extra space just for installing (even temporarily) and because it wastes time in doing so.
Copy the APK file, telling it to avoid actual copy (meaning hard link), using this command (taken from here) :
cp -p -r -l $fullPathToApkFile $tempFileParentPath"
This didn't work. It got me this error:
cp: /data/local/tmp/test.apk: Cross-device link
Checking what happens in other cases of installing apps. When you install via via the IDE, it actually does create the APK file in this special path, but if you install via the Play Store, simple APK install (via Intent) or adb (via PC), it doesn't.
Wrote about this here too: https://issuetracker.google.com/issues/80270303
The questions
Is there any way to overcome the disadvantages of installing the APK using root on this special path? Maybe even avoid handling this path at all?
Why does the OS suddenly require to use this path? Why not use the original path instead, just like in the other methods of installing apps? What do the other methods of installing apps do, that somehow avoids using the spacial path?
One solution, in case you don't mind the moving procedure, is to also save&restore the timestamp of the original file, as such:
val tempFileParentPath = "/data/local/tmp/"
val tempFilePath = tempFileParentPath + File(fullPathToApkFile).name
val apkTimestampTempFile = File(context.cacheDir, "apkTimestamp")
apkTimestampTempFile.delete()
apkTimestampTempFile.mkdirs()
apkTimestampTempFile.createNewFile()
root.runCommands("touch -r $fullPathToApkFile ${apkTimestampTempFile.absolutePath}")
root.runCommands("mv $fullPathToApkFile $tempFileParentPath")
root.runCommands("pm install -t -f $tempFilePath")
root.runCommands("mv $tempFilePath $fullPathToApkFile")
root.runCommands("touch -r ${apkTimestampTempFile.absolutePath} $fullPathToApkFile")
apkTimestampTempFile.delete()
It's still a bit dangerous, but better than copying files...
EDIT: Google has shown me a nice workaround for this (here) :
We don't support installation of APKs from random directories on the device. They either need to be installed directly from the host using 'adb install' or you have to stream the contents to install --
$ cat foo.apk | pm install -S APK_SIZE
While I think this is incorrect that they don't support installing of APK files from random paths (always worked before), the workaround does seem to work. All I needed to change in the code of installing an APK file is as such:
val length = File(fullPathToApkFile ).length()
commands.add("cat $fullPathToApkFile | pm install -S $length")
Thing is, now I have some other questions about it :
Does this workaround avoid the moving/copying of the APK into storage, and without affecting the original file ? - seems it does
Will this support any APK file, even large ones? - seems it succeeds in doing it for an APK that takes 433MB, so I think it's safe to use for all sizes.
This is needed only from Android P, right? - so far seems so.
Why does it need the file size as a parameter ? - No idea, but if I remove it, it won't work
Thanks for the answers! I looked everywhere else as well to get a whole setup for OTA to work for Android 10 and so on. It 100% works on Samsung Galaxy Tab 10.1 running Android 10.
Here is a medium article with the code:
https://medium.com/#jnishu1996/over-the-air-ota-updates-for-android-apps-download-apk-silent-apk-installation-auto-launch-8ee6f342197c
The magic is running this command with root access:
process = Runtime.getRuntime().exec("su");
out = process.getOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(out);
// Get all file permissions
dataOutputStream.writeBytes("chmod 777 " + file.getPath() + "\n");
// Perform silent installation command, all flags are necessary for some reason, only this works reliably post Android 10
String installCommand = "cat " + file.getAbsolutePath() + "| pm install -d -t -S " + file.length();
// Data to send to the LaunchActivity to the app knows it got updated and performs necessary functions to notify backend
// es stands for extraString
// In LaunchActivity onCreate(), you can get this data by running -> if (getIntent().getStringExtra("OTA").equals("true"))
String launchCommandIntentArguments = "--es OTA true --es messageId " + MyApplication.mLastSQSMessage.receiptHandle();
// Start a background thread to wait for 8 seconds before reopening the app's LaunchActivity, and pass necessary arguments
String launchCommand = "(sleep 8; am start -n co.getpresso.Presso/.activities.LaunchActivity " + launchCommandIntentArguments + ")&";
// The entire command is deployed with a ";" in the middle to launchCommand run after installCommand
String installAndLaunchCommand = installCommand + "; " + launchCommand;
// begins the installation
dataOutputStream.writeBytes(installAndLaunchCommand);
dataOutputStream.flush();
// Close the stream operation
dataOutputStream.close();
out.close();
int value = process.waitFor();
I'm trying to run some commands on an application that is already installed through monkeyrunner. I've edited the sample code listed on d.android.com and I changed it to this:
# Imports the monkeyrunner modules used by this program
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
# Connects to the current device, returning a MonkeyDevice object
device = MonkeyRunner.waitForConnection()
# Installs the Android package. Notice that this method returns a boolean, so you can test
# to see if the installation worked.
device.installPackage('myproject/bin/MyApplication.apk')
# sets a variable with the package's internal name
package = 'com.example.myTestApp'
# sets a variable with the name of an Activity in the package
# activity = 'com.example.android.myapplication.MainActivity'
# sets the name of the component to start
runComponent = package
# Runs the component
device.startActivity(component=runComponent)
# Presses the Menu button
device.press('KEYCODE_MENU', MonkeyDevice.DOWN_AND_UP)
# Takes a screenshot
result = device.takeSnapshot()
# Writes the screenshot to a file
result.writeToFile('myproject/shot1.png','png')
As you can see, I changed the code to (hopefully) open com.example.myTestApp But it doesn't open my application, but it seems it runs the commands on the current application. Any ideas?
You should specify the Activity in runComponent as
runComponent = package + "/" + activity
To get the names of the launchable Activities:
$ aapt dump badging <name>.apk | grep launchable-activity
I was able to get the launch activity from an any installed apk from the play store using this method:
get launchable activity name of package from adb
adb shell pm list packages -f
Then you can use adb pull:
adb pull <APK path from previous command> <toYourDesiredLocation>
For Example:(adb pull /system/app/MyAPK.apk C:\someLocation)
and then aapt to get the information you want (aapt is currently located in ~\sdk\build-tools\android-4.3):
aapt dump badging <FromYourDesiredLocation\pulledfile.apk>
then look for launchable-activity: name='SomeActivityName'
Hope that helps someone else looking for the same thing.
First check whether your app is installed.
apk_path = device.shell('pm path com.xx.yy')
if apk_path.startswith('package:'):
print "XXXYY already installed."
else:
print "XXXYY app is not installed, installing APKs..."
device.installPackage('D:/path to apk/yourapp.apk')
refer http://antoine-merle.com/introduction-to-the-monkey-runner-tool-2/
If I do:
adb install myAppRelease-2012-07-24_14-35-14.apk
When I try to reference the actual .apk file after it is installed
PackageManager pm = this.getPackageManager();
for (ApplicationInfo app : pm.getInstalledApplications(PackageManager.GET_META_DATA)) {
Log.d("PackageList", "package: " + app.packageName + ", sourceDir: " + app.sourceDir);
String appName = "myAppRelease"
if(app.packageName.contains("myApp")){
if(app.sourceDir.contains(appName)){
apkVersion = app.sourceDir.substring(app.sourceDir.indexOf(appName), app.sourceDir.indexOf(apk));
}
}
}
What I see is this:
07-24 14:46:40.190: D/PackageList(7421): package: myApp, sourceDir: /data/app/myApp-1.apk
What I expected to see is this:
07-24 14:46:40.190: D/PackageList(7421): package: myApp, sourceDir: /data/app/myAppRelease-2012-07-24_14-35-14.apk
It appears that it uses
android:label="myApp"
android:versionCode="1"
from the manifest file.
My question is, why doesn't it keep the original .apk filename? I am relying on the .apk filename to display version information for my app.
You can't rely on this, and it definitely doesn't use the version code for the number after the '-'. Especially with newer versions, apps can be moved to the SD card, or forward locked (aka, 'app encryption'), so the actual file on disk can be very different from the original file.
Use PackageManager to get version info, that is guaranteed to be correct and up to date. Change your build system to update the version code and maybe display it in an About dialog or similar so it is easy for users to report it.
My application contains some list of *.apk files.
I know only the application(example.apk) name.
How to identify this application(example.apk) package name through programmatically.
Is it possible.
Thanks in advance.
This will loop through installed applications and get package name and path to apk.
Assuming you have the ApplicationInfo for your apk, you can do the same approach as here (without loop).
PackageManager pm = getPackageManager();
for(ApplicationInfo app : pm.getInstalledApplications(0)) {
Log.d("PackageList", "package: " + app.packageName + ", sourceDir: " + app.sourceDir);
}