I would like to create a file which stores some data that can be accessed only by my app.Outside users should not be able to access this file or make any changes to it.I will store a key in the file which maybe accessed by the app whenever needed.
Use Environment.getDataDirectory(),
http://developer.android.com/reference/android/os/Environment.html#getDataDirectory()
This gives a File object that is the path to a private, app specific data directory. The files created therein are owned by your app's user ID, preventing any other app from accessing them.
File myPrivateFile = new File(Environment.getDataDirectory(), context.getPackageName() + File.separator + "secret.txt");
Note that if the device is rooted, all bets are off. A root process can read any file on the device. The best you can do is only store information for user of the device. That way if it's compromised, only one user account is compromised. In other words, don't store credentials, keys, access tokens, etc. That would allow a malicious agent access to a server where it could steal data for other users.
To create an application private file (that is not readable by other applications) you should use Context.openFileOutput() with a flag MODE_PRIVATE.
If you are concerned you could wrap the returned InputStream in CiperOutputStream and encrypt the contents.
If you are storing keys in a standard crypto format (X.509 or PKCS#12) you could use the new KeyChain API introduced in ICS.
Why not just stored it in a SharedPreference ??
Make your SharedPreference private to your activity by calling..
getSharedPreferences(yourfile, MODE_PRIVATE);
This will make sure only your Activity can access that SharedPreference.
To open a file from a private app folder, one can use this file path:
File myFilePath = new File(getContext().getFilesDir() + File.separator + "myFile")
You can check if the file exists if(myFilePath.exists()) ...
To save a text file to the private app directory
FileOutputStream fos = null;
try {
fos = getContext().openFileOutput("myFile",Context.MODE_PRIVATE);
} catch (FileNotFoundException e) { }
try {
fos.write(myTextString.getBytes());
} catch (IOException e) { }
try {
fos.close();
} catch (IOException e) { }
To save an image to the private app directory:
try {
myBitmapImage.compress(CompressFormat.JPG, 90,
openFileOutput("myimage.jpg", MODE_PRIVATE));
} catch (Exception e) { }
Your best bet is to store an encrypted file and decrypt it run-time, so even a rooted phone would not be able to read your data even if it has access to it. Of course, it's a chicken-egg condition (where would you store your key for the encrypted file), and the only thing better than putting the key in a variable is to generate that key runtime using some obscure method (see this)
Related
so i know there are alot of questions about creating a text file in android but i cant find any answers to my specific questions.
So the device I'm using is not an phone or a tablet, its a controller with android on it so the file directory is getting me confused. i want to create a new file either on the sd card or the device itself (it doesn't really matter as long as i can see it). firstly, the device doesn't have google docs or sheets or anything like that, will i need to install one of these apps on it for it to be able to read .txt files? or does android have some sort of internal software to do that?
Secondly, i've found alot of code on how to create a new file but most of it seems to gloss over how to get file directory, is there a specific way i can get the file directory?
This is what im using so far and im not getting any errors but its also not creating any files (or at-least none that i can see).
public void WriteToText(){
String FILENAME = "hello_file";
String string = "hello world!";
FileOutputStream fos = null;
try {
fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
1, I think all devices have Html viewer which can view the text files. If you click a text file in a file manager app, it should prompt you with a list of apps that can view the text file.
2, Your code is correct, but it creates a file in the app's private file directory, which is not visible to all other apps, including file manager apps. This is because of Android security policy to prevent any app to steal information from other apps.
If you want to write a file which is visible to other apps like file manager, there are 2 ways.
in old api level (<29?) you can get the get external storage with
Environment.getExternalStorageDirectory()
you will need to request permission for it.
save the file in your app's private directory like what you have done, then create a chooser to share it out with correct mime type (txt/plain?), it will prompt you to select app that can view this mime type like what file manager does.
I am trying to transfer a file using googles Nearby Connections API. Largely I can get all components of the transfer to work so that all of the files data is transferred but the issue is that the files data is then stored in Nearby's scoped storage so I am unable to access it from my app to be able to process that data into the appropriate file type and then save and rename as necessary.
The current method I am using to try and process the payload is
private void processFilePayload(long payloadId) {
// BYTES and FILE could be received in any order, so we call when either the BYTES or the FILE
// payload is completely received. The file payload is considered complete only when both have
// been received.
Payload filePayload = completedFilePayloads.get(payloadId);
String filename = filePayloadFilenames.get(payloadId);
if (filePayload != null && filename != null) {
completedFilePayloads.remove(payloadId);
filePayloadFilenames.remove(payloadId);
// Get the received file (which will be in the Downloads folder)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
File fromPayload = filePayload.asFile().asJavaFile();
Uri uri = Uri.fromFile(fromPayload);
try {
// Copy the file to a new location.
InputStream in = getApplicationContext().getContentResolver().openInputStream(uri);
copyStream(in, new FileOutputStream(new File(getApplicationContext().getCacheDir(), filename)));
} catch (IOException e) {
// Log the error.
Log.e("copy file", e.toString());
} finally {
// Delete the original file.
getApplicationContext().getContentResolver().delete(uri, null, null);
}
} else {
File payloadFile = filePayload.asFile().asJavaFile();
// Rename the file.
payloadFile.renameTo(new File(payloadFile.getParentFile(), filename));
}
}
}
});
Because of android 11's scoped storage to be able to access the file the files Uri needs to be used to create an input stream with a content resolver to access the file.
According to the Nearby Documentation there should be a method Payload.File.asUri so I would be able to use the line Uri payloadUri = filePayload.asFile().asUri(); but this is not actually available in the API despite using the most recent version of Nearby.
As well as this the use of Payload.File.AsJavaFile() should be deprecated according to the google Nearby documentation
I have seen some other answers for similar problems where the suggestion is to use Media.Store but this is not possible as the file does not have any extension yet so doesn't show up as any particular file type.
Note: I have requested read/write external storage permissions both in the manifest and at runtime.
===Update===
Payload.asFile.asUri() is available in com.google.android.gms:play-services-nearby:18.0.0
============
Sorry about that. We'll be releasing an update soon with #asUri properly exposed.
In the meantime, if you target API 29, you can use requestLegacyExternalStorage=true as a workaround. (See more: https://developer.android.com/about/versions/11/privacy/storage)
One of our app requirements is that some SQLite file should be retained and backup, even the app is uninstalled.
We achieve such, by writing SQLite file via Room, into location Environment.getExternalStorageDirectory
RoomDatabase with customizable SQLite file path
#Database(
entities = {Backup.class},
version = 1
)
public abstract class LocalBackupNamedRoomDatabase extends RoomDatabase {
public abstract BackupDao backupDao();
public static LocalBackupNamedRoomDatabase newInstance(String dbName) {
LocalBackupNamedRoomDatabase INSTANCE = Room.databaseBuilder(
WeNoteApplication.instance(),
LocalBackupNamedRoomDatabase.class,
dbName
)
.build();
return INSTANCE;
}
}
Function returns Environment.getExternalStorageDirectory
public static String getBackupDirectory() {
if (backupDirectory == null) {
File _externalStorageDirectory = Environment.getExternalStorageDirectory();
if (_externalStorageDirectory == null) {
return null;
}
try {
backupDirectory = _externalStorageDirectory.getCanonicalPath();
} catch (IOException e) {
Log.e(TAG, "", e);
}
if (backupDirectory == null) {
return null;
}
backupDirectory = toEndWithFileSeperator(backupDirectory) + "com.yocto.wenote" + File.separator + "backup" + File.separator;
}
return backupDirectory;
}
How we save SQLite file via Room in external storage
LocalBackupNamedRoomDatabase.newInstance(
getBackupDirectory() + "local-backup"
).backupDao().insert(backup)
According to this, my understanding is that Environment.getExternalStorageDirectory might not be usable anymore (am I correct??).
My guess is that, in order to achieve the same behavior, I might need to use MediaStore.Downloads? But how?
Can anyone provide a concrete example for the above use case? Or, we are no longer possible to achieve such behavior, under Scoped storage?
From my own experiments with the Q beta 2 emulator, with a test app with targetSdkVersion 'Q':
Initially Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).exists() was false, which led me to believe you can't even access it in Q. Then I found mkdirs() worked, and I could then read and write to a sandboxed view of this folder restricted to my app's files only. This has the interesting side effect that multiple apps can write files with the same name to the 'download' folder, and that's how they show in the default files app on the emulator!
As the docs mention, you lose access to your own files after uninstall then reinstall. So, in order to restore a sqlite file from downloads after uninstall, you'd have to:
"allow the user to choose a file using the system's file picker app." (from docs)
This will give you a URI rather than a File. Because SQLiteDatabase can only read Files, you'll need to open the URI as a stream and write it to a real file somewhere you control, eg cache or internal storage.
This is a pain, but doable for most use cases. It gets tricky for very large database files, eg mapbox tiles which may be hundreds of mb or more, stored on an actual SD card because they won't fit on regular 'external' storage.
As stated here, the files located in your external storage will be removed upon uninstallation of your application. Hence, you might consider using getExternalStoragePublicDirectory function to store your files in the top level shared storage. If you want to store in the DOWNLOADS directory, you can use the following to get the directory path.
File path = Environment.getExternalStoragePublicDirectory(
Environment. DIRECTORY_DOWNLOADS);
Hope that helps.
I have this piece of code for saving accelerometer data in a file , but i cant find that file in my internal storage.
String file_name="hello_file";
try {
FileOutputStream fileOutputStream=openFileOutput(file_name, Context.MODE_PRIVATE);
fileOutputStream.write(message.getBytes());
fileOutputStream.close();
Toast.makeText(getApplicationContext(),"saved",Toast.LENGTH_LONG).show();
acceleration.setText("");
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
getFilesDir() gives the location of where openFileOutput() writes files.
That said, those files are not accessible by users. They could access them actually but if they had a rooted device at hand.
Here's a tutorial regarding Internal and External storage.
I don't know how much you know about Android storage but just to clarify External isn't really external in the sense of an external hard-drive. It's external as on a different partition from the one holding the OS. It is still 'internal' in the sense that it's not on an sdcard. But still even if you don't have an SD card installed, Android could name your external(non-system) storage sdcard/ .... So yeah, lots of confusion initially.
Hi I have a project that should save a JSON Array to internal storage.
Here's my code:
public void createFile(String data){
try{
FileOutputStream fos = openFileOutput("userObj", Context.MODE_PRIVATE);
fos.write(data.getBytes());
fos.close();
Log.d(TAG, "Successfully created userObj file.");
}catch (Exception e){
Log.d(TAG, "Failed to create userObj " + e);
}
}
but when I'm calling createFile(response);
I'm getting
java.lang.NullPointerException at android.content.ContextWrapper.openFileOutput(ContextWrapper.java:180)
check whether you have the permission WRITE_EXTERNAL_STORAGE no matter you use internal storage or external storage.
check whether the file path is correct. You have to create the file path by Environment.getExternalStorageDirectory ()
Note: don't be confused by the word "external" here. This directory
can better be thought as media/shared storage. It is a filesystem that
can hold a relatively large amount of data and that is shared across
all applications (does not enforce permissions). Traditionally this is
an SD card, but it may also be implemented as built-in storage in a
device that is distinct from the protected internal storage and can be
mounted as a filesystem on a computer.
I'm getting java.lang.NullPointerException at android.content.ContextWrapper.openFileOutput(ContextWrapper.java:180
You don't have a valid Context you're working with.
Likely it's an Activity you have instantiated yourself with new. Don't do that. Activities should only by instantiated via an Intent by the framework. If you need to pass a Context around, pass a reference to a framework-initialized Context object such as an Activity around.