In Android, how do I get the application's id programatically (or by some other method), and how can I communicate with other applications using that id?
If your are looking for the value defined by applicationId in gradle, you can simply use
BuildConfig.APPLICATION_ID
EDIT 2022:
As indicated in the comments, BuildConfig.APPLICATION_ID is deprecated, but for librairies only. In this case, BuildConfig.LIBRARY_PACKAGE_NAME should be used instead, as explained here.
Also, now, Context::getPackageName returns the value defined by applicationId in gradle, even if you have several flavors with different applicationId (with a unique namespace), see here.
If by application id, you're referring to package name, you can use the method Context::getPackageName (http://http://developer.android.com/reference/android/content/Context.html#getPackageName%28%29).
In case you wish to communicate with other application, there are multiple ways:
Start an activity of another application and send data in the "Extras" of the "Intent"
Send a broadcast with specific action/category and send data in the extras
If you just need to share structured data, use content provider
If the other application needs to continuously run in the background, use Server and "bind" yourself to the service.
If you can elaborate your exact requirement, the community will be able to help you better.
i'm not sure what "application id" you are referring to, but for a unique identifier of your application you can use:
getApplication().getPackageName() method from your current activity
For getting AppId (or package name, how some says), just call this:
But be sure that you importing BuildConfig with your app id packages path
BuildConfig.APPLICATION_ID
Package name is your android app id .
String appId = BuildConfig.APPLICATION_ID
Or
https://play.google.com/store/apps/details?id=com.whatsapp
App Id = com.whatsapp
Else you can get id of process your application runs in:
final static int android.os.Process.myPid()
Returns the identifier of this process, which can be used with killProcess(int) and sendSignal(int, int).
I am not sure what you need the app/installation ID for, but you can review the existing possibilities in a great article from Android developers:
http://android-developers.blogspot.com/2011/03/identifying-app-installations.html
To sum up:
UUID.randomUUID() for creating id on the first time an app runs after installation and simple retrieval afterwards
TelephonyManager.getDeviceId() for actual device identifier
Settings.Secure.ANDROID_ID on relatively modern devices
Step 1: Open the Google Play Store
Step 2: Open any App in App Store
Example: facebook
Step 3: Click on any App and Look at the Browser link and At the End id=com.facebook.katana&hl=en will be there and this is your Apps Unique Id.
The PackageInfo.sharedUserId field will show the user Id assigned in the manifest.
If you want two applications to have the same userId, so they can see each other's data and run in the same process, then assign them the same userId in the manifest:
android:sharedUserId="string"
The two packages with the same sharedUserId need to have the same signature too.
I would also recommend reading here for a nudge in the right direction.
If the whole purpose is to communicate data with some other application, use Intent's sendBroadcast methods.
If you are using the new** Gradle build system then getPackageName will oddly return application Id, not package name. So MasterGaurav's answer is correct but he doesn't need to start off with ++
If by application id, you're referring to package name...
See more about the differences here.
** not so new at this point
++ I realize that his answer made perfect sense in 2011
Android App ES File Explorer shows the Android package name in the User Apps section which is useful for Bitwarden. Bitwarden refers to this as "android application package ID (or package name)".
To track installations, you could for example use a UUID as an identifier, and simply create a new one the first time an app runs after installation. Here is a sketch of a class named “Installation” with one static method Installation.id(Context context). You could imagine writing more installation-specific data into the INSTALLATION file.
public class Installation {
private static String sID = null;
private static final String INSTALLATION = "INSTALLATION";
public synchronized static String id(Context context) {
if (sID == null) {
File installation = new File(context.getFilesDir(), INSTALLATION);
try {
if (!installation.exists())
writeInstallationFile(installation);
sID = readInstallationFile(installation);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return sID;
}
private static String readInstallationFile(File installation) throws IOException {
RandomAccessFile f = new RandomAccessFile(installation, "r");
byte[] bytes = new byte[(int) f.length()];
f.readFully(bytes);
f.close();
return new String(bytes);
}
private static void writeInstallationFile(File installation) throws IOException {
FileOutputStream out = new FileOutputStream(installation);
String id = UUID.randomUUID().toString();
out.write(id.getBytes());
out.close();
}
}
Yon can see more at https://github.com/MShoaibAkram/Android-Unique-Application-ID
This is now deprecated you should use BuildConfig.LIBRARY_PACKAGE_NAME as answered here
Related
I have folders on my Google Drive account and i want to add files in specific folder. How can I do it? In example needed DriveId (EXISTING_FOLDER_ID), but I don't know DriveID my folder, I know name only.
#smokybob. I don't know if it helps with the original question, but per your comment:
Here's a code snippet that should get you folder/file DriveId. The 'title', 'mime' and 'fldr' arguments are optional. In case you pass null for 'fldr', the search is global (within the app's FILE scope), otherwise within the specified folder (not in subfolders, though). It uses the simplest - 'await()' flavor, that has to be run off the UI thread.
Be careful though, the folder / file names are not unique entities in the Google Drive Universe. You can have multiple files / folders with the same name in a single folder !
GoogleApiClent _gac; // initialized elsewhere
//find files, folders. ANY 'null' ARGUMENT VALUE MEANS 'any'
public void findAll(String title, String mime, DriveFolder fldr) {
ArrayList<Filter> fltrs = new ArrayList<Filter>();
fltrs.add(Filters.eq(SearchableField.TRASHED, false));
if (title != null) fltrs.add(Filters.eq(SearchableField.TITLE, title));
if (mime != null) fltrs.add(Filters.eq(SearchableField.MIME_TYPE, mime));
Query qry = new Query.Builder().addFilter(Filters.and(fltrs)).build();
MetadataBufferResult rslt = (fldr == null) ?
Drive.DriveApi.query(_gac, qry).await() :
fldr.queryChildren(_gac, qry).await();
if (rslt.getStatus().isSuccess()) {
MetadataBuffer mdb = null;
try {
mdb = rslt.getMetadataBuffer();
if (mdb != null) {
for (Metadata md : mdb) {
if (md == null) continue;
DriveId dId = md.getDriveId(); // here is the "Drive ID"
String title = md.getTitle();
String mime = md.getMimeType();
// ...
}
}
} finally { if (mdb != null) mdb.close(); }
}
}
In general terms, you can get the 'DriveId' you need from:
file / folder name as shown in the code above, or
the string identifier you've got from 'encodeToString()'. I use it for caching MYROOT folder id, for instance, or
the string identifier you've got from 'getResourceId()'. This is the string you see in the html address. But since your only scope is FILE, don't count on using it to open something your app did not create.
Both 2 and 3 identifiers are strings, so they may be confused. Identifier 2 is faster when retrieving Drive ID (via decodeFromString()). Identifier 3 is slower to retrieve (via fetchDriveId()), but usefull if you need to take your ID elsewhere (Apps Script, for instance). See also SO 21800257
As far as creation of files / folders is concerned, I have some code on GitHub here. If you look at awaits\MainActivity.java ... buildTree(), you will see the creation of folders / files recursively when building a simple folder tree.
OK. I experienced the same issue with the Drive demos on Github: https://github.com/googledrive/android-demos
At the bottom of the readme, it says:
If you actually want to run this sample app (though it is mostly
provided so you can read the code), you will need to register an OAuth
2.0 client for the package com.google.android.gms.drive.sample.demo with your own debug keys and set any resource IDs to those that you
have access to. Resource ID definitions are on:
com.google.android.gms.drive.sample.demo.BaseDemoActivity.EXISTING_FOLDER_ID
com.google.android.gms.drive.sample.demo.BaseDemoActivity.EXISTING_FILE_ID
They didn't really specify how exactly one should get and set the resourceID for the EXISTING_FOLDER_ID and EXISTING_FILE_ID constants defined in the BaseDemoActivity file and after reading seanpj comment above, I used his method number 3 to find the DriveIDs so that I can add it to the demo app so that it runs properly.
All one needs to do is to go to Drive on your PC then click on the "link" button at the top.
A portion of the link says "id=XXXXXXXXXXX". Copy that and paste it into the BaseDemoActivity file in the demo app. Do this for both a file and a folder that you create yourself on Drive.
The Demo app should now run successfully.
you can use query to find folder
Query query = new Query.Builder().addFilter(Filters.and(
Filters.eq(SearchableField.TITLE, "folder name"),
Filters.eq(SearchableField.TRASHED, false))).build();
I fount one sample tutorial
http://wiki.workassis.com/android-google-drive-api-deleted-folder-still-exists-in-query/
in this tutorial they are calling asynchronously
If you have the metadata for the folder (or a DriveFolder object, from which you can get the metadata), you can just call getDriveId.
If you have the web resource, you can get the DriveId using that resource id using fetchDriveId
Having Google Drive account with folders and files. I want to make android application for adding and geting files to there. Class QUERY is useful, but it can work with data making by application only
The Android Drive API only works with the https://www.googleapis.com/auth/drive.file scope. This means that only files which a user has opened or created with your application can be matched by a query.
Help, please, how can I add files to any folder, that was created via webinterface early?
You want to avoid using full drive scope unless you really need it. Users much prefer that your app have a narrower scope, as it makes it easier to trust you with their data. There are a couple of methods that you can accomplish most folder use cases while still only requiring file scope:
Use the OpenFileActivity to have the user select the folder that they want the file to be added to.
You can do this by configuring the OpenFileActivityBuilder to only display the folder mimetypes.
IntentSender intent = driveApi.newOpenFileActivityBuilder()
.setActivityTitle("Pick a destination folder")
.setMimeType(new String[] { DriveFolder.MIME_TYPE } })
.build();
startIntentSenderForResult(intent, REQUEST_CODE, null, 0, 0, 0);
Alternatively, if you have a corresponding web app that created the folder, just use the same developer console entry for both apps and you should already have access to the folder.
Don't use the latest google API, it was just released a few weeks ago. It currently only works with the drive.file scope, hasn't yet implemented a number of capabilities (e.g. setting multiple parents), and in my experience, contains some bugs that need to be fixed as well.
com.google.android.gms.common.api.GoogleApiClient
Use this API instead:
com.google.api.services.drive.Drive
try {
List<String> scopes = new ArrayList<String>();
scopes.add("https://www.googleapis.com/auth/drive.appdata");
scopes.add(DriveScopes.DRIVE);
GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(m_context, scopes);
credential.setSelectedAccountName(m_account.name);
//Get token cannot be run from the main thread;
//Trying to get a token right away to see if we are authorized
token = credential.getToken();
if(token == null){
Log.e(TAG, "token is null");
}else{
Log.i(TAG, "GDrive token: " + token);
g_drive = new Drive.Builder(
AndroidHttp.newCompatibleTransport(),
new GsonFactory(), credential).build();
} catch ( UserRecoverableAuthException e) {
....
}
Can we clear or delete data of one application from another application in android. If it is not possible simply could you please suggest any tricky way to do this like to go to the folder in internal memory and delete that folder programatically.
Thanks.
Simple answer,
Android is designed that this should not be possible.
But when using root access you can actually delete folders from other applications.
I believe if two applications having a different package, but with the same signature, actually can have access to each others private folders. Or i'm not sure, i believe you could add some kind of declaration to you manifest file allowing other (friend) apps to have access to your private folder. But i'm not sure i should search for it.
Edit after search:
Apps having the same android:sharedUserId and android:sharedUserLabel and signature have access to each others private files.
http://developer.android.com/guide/topics/manifest/manifest-element.html#uid
Two Android applications with the same user ID
Edit 2:
There are some private methods in the android API, witch can be used to clear app data i think. I'm not sure but if you reflect those methods with the right permissions in you manifest file it could be possible to clear app data, but i'm not 100% sure.
Some small example code:
Method clearApplicationUserData = getReflectedMethod("clearApplicationUserData", String.class, IPackageDataObserver.class);
And the method i use the get it reflected...
private Method getReflectedMethod(String methodname, Class<?>... args) {
Method temp = null;
try {
temp = pm.getClass().getMethod(methodname, args);
} catch (SecurityException e) {
return null;
} catch (NoSuchMethodException e) {
return null;
}
return temp;
}
The IPackageDataObserver class should be copied from the original android source, and added as new class in the source folder of your project under the package android.content.pm.
When you want to clear user data i think you should invoke the method like this:
public void clearApplicationUserData(String packageName) {
if (clearApplicationUserData != null) {
try {
clearApplicationUserData.invoke(pm, packageName, data_helper);
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
}
}
The data_helper is any class extending the IPackageDataObserver.Stub class.
You can find a lot of questions about reflecting methods and stuff here on stackoverflow.
I have no idea if this works but this is the only way i can think of.
Rolf
If its stored in the database you can delete the data using content provider by following method
mRowsDeleted = getContentResolver().delete(
UserDictionary.Words.CONTENT_URI, // the user dictionary content URI
mSelectionClause // the column to select on
mSelectionArgs // the value to compare to
);
follow the methods Here
The question is not very clear.
Do you mean your app will delete data from someone elses app? The answer there is "it depends". First, if the data is on the SD card, you could access it and delete it. If the data is in the apps private data area, then you cannot do that unless your phone is rooted.
If the apps in question are both made by you, the answer is yes, it is possible. You would have to use the android:sharedUserId property in the manifest file of each app, make them the same and sign both apps with the same key. This would give the apps access to each others data.
If the data you are speaking of is on the devices SD card, yes you can. If it is in the internal storage, then no (unless you created both apps and have used the
The final objective will be clear shortly.
I want to create a file object and instead of getting data from a real physical file I want to provide the buffer myself.
Then, I want to use this file, which does not really exist in the sdcard or anywhere outside my app, give it a name and send it by email as an attachment (using the EXTRA_STREAM).
I found the following bit of code, by Adriaan Koster (#adriaankoster), the post Write byte[] to File in Java
// convert byte[] to File
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
File fileFromBytes = (File) ois.readObject();
bis.close();
ois.close();
System.out.println(fileFromBytes);
I used it to create this function
private File fileFromBytes(byte[] buf) {
File f = null;
try {
ByteArrayInputStream bis = new ByteArrayInputStream(buf);
ObjectInputStream ois = new ObjectInputStream(bis);
f = (File) ois.readObject();
bis.close();
ois.close();
}
catch (Exception e) {}
return f;
}
and here is where I am stuck, because when I use it:
// When sent as body the mail is sent OK
// emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, dump());
// When I try to attach the mail is empty
emailIntent.putExtra(android.content.Intent.EXTRA_STREAM, fileFromBytes(dump().getBytes()));
I know from examples I've seen the second argument should be an URI, but: How do I create a virtual URI to fit my file?
EDIT:
The option to attach data directly from within the application is important to certain kind of applications. Namely, security & banking applications that do not want to move sensitive data around too much. Surely if the data does not reach the sdcard and goes directly to a mail attachment it is harder to sniff than within the application memory.
This is not my specific case, but I wanted to point out that this capability is important to have.
The first thing you'll want to do, I imagine, is create a ContentProvider. You can see an example implementation here
https://github.com/dskinner/AndroidWeb/blob/master/src/org/tsg/web/WebContentProvider.java
where in the above link's case, you would add this to your AndroidManifest.xml
<provider
android:name="org.tsg.web.WebContentProvider"
android:authorities="your.package.name" />
Now, you'll have a content uri available for use, content://your.package.name/.
The portion of the above ContentProvider your interested in, again I imagine, is the openFile method. When sharing data by intent across apps, certain things are expected. In your case, you're looking to share some byte data that's meant to be attached to the email.
So if you pass in a content uri to the email app such as content://your.package.name/foo with the appropriate intent flags, then openFile will get called on your ContentProvider. In this case, you can inspect the end of the uri segment to see foo was requested, and return appropriately.
The next issue you bring up is not having the file actually on disk. While I can't vouch for the method you used above (though it looks kosher), what you need to be returning is a ParcelFileDescriptor from your ContentProvider. If you look at the link I provided, you could possibly try to use that as a sample to get the file descriptor from your File object (my knowledge waivers here), but I imagine, the data simply wont be available at that point.
What you do bring up is security though. It's important to note that you can write data to disk privately so only the app has access to the data. I believe, but you might want to double check on this, if that data is private to the app, you can expose it via the ContentProvider and possibly lock down who and how the provider gets used, who can call it, etc. You may want to dig into android docs for that portion or look at some other SO questions.
Anyway, good luck.
Create the file in the application's cache directory. It will be created in the internal filesystem. Use 'getCacheDir()' API for getting the path to the cache dir. Write the data into this dir and then get the URI from the File object using ' Uri.fromFile (File file) '. When you are finished with the file, delete it.
Your application's cache is only available to your app, hence its safe to use for your purpose.
You can do some encryption if the data is too critical.
I think in order to do this, you are going to have to expose a ContentProvider, which will allow you handle a URI. The email application should then openInputStream on your URI, at which point you return an InputStream on your in-memory data.
I've not tried it, but in theory this should work.
i was busy with adding attachment to mail and i can send mail with attachment.
if you want to take a look: can not send mail with attachment in Android
I am creating a framework to be used by many departments in my work environment. I need a way to dynamically load classes into the framework from individual department apk's. For instance a way to dynamically load department A's content provider class into the framework.
I have had little luck trying to figure this out, any help would be much appreciated. Thanks.
If you want to load an already known class from another .apk currently installed on your device you can take the following approach (assuming your class has a default constructor). Also please remember that you must know the package name of the other .apk file and the other .apk file's package name must be different from your applications package name.
private Object loadClass(String packageName, String className){
Object plugin = null;
try {
PackageManager packageManager = getPackageManager();
ApplicationInfo appInfo = packageManager.getApplicationInfo(packageName, 0);
DexFile df = new DexFile(appInfo.sourceDir);
ClassLoader cl = getClassLoader();
Class classToInvestigate = df.loadClass(className, cl);
plugin = classToInvestigate.newInstance();
} catch (Exception e) {
System.out.println("EXCEPTION");
}
finally{
return plugin;
}
}
I expect it would be a security hole if this was allowed and your design is risky as you are tightly coupling your program to someone else's.
A better solution is to be able to just use the content provider from your activity, much as you can access the contacts in Android.