How to extract files from .obb file? - android

in my application I downloaded the expansion file at Android->obb->packagename->main.1.packagename.obb .
Can someone explain to me, even with the sample code how to extract my files from it ?
I tried to use the APK Expansion Zip Library as :
ZipResourceFile expansionFile = APKExpansionSupport.getAPKExpansionZipFile(MainActivity.this, 3, 0);
for (ZipResourceFile.ZipEntryRO entry : expansionFile.getAllEntries())
Log.d("",entry.mFileName);
InputStream input = expansionFile.getInputStream(Environment.getExternalStorageDirectory().toString()
+ "/sdcard/Android/obb/com.example.project/main.3.com.example.project.obb/obb/file.zip/file.apk");
But expansionFile is always null.
The .obb file was created with Jobb, used on the folder obb/file.zip .

Solved with the following code:
final StorageManager storageManager = (StorageManager) getSystemService(STORAGE_SERVICE);
String obbPath = Environment.getExternalStorageDirectory() + "/Android/obb";
final String obbFilePath = obbPath + "/com.example.project/main.3.com.example.project.obb";
OnObbStateChangeListener mount_listener = new OnObbStateChangeListener() {
public void onObbStateChange(String path, int state) {
if (state == OnObbStateChangeListener.MOUNTED) {
if (storageManager.isObbMounted(obbFilePath)) {
Log.d("Main","Mounted successful");
String newPath = storageManager.getMountedObbPath(obbFilePath);
File expPath = new File(newPath+"/file.zip/file.apk");
Log.d("Main","File exist: " + expPath.exists());
}
}
}
};
storageManager.mountObb(obbFilePath, "key", mount_listener);
After mounting the .obb file , I can access my data in the path mnt/obb/myfolder .

I used this for reading a specific file from the obb:
In your AndroidManifest.xml:
<!-- Needed for reading the obb file -->
<provider
android:name=".extension.ZipFileContentProvider"
android:authorities="com.example.extension.ZipFileContentProvider"/>
ZipFileContentProvider:
public class ZipFileContentProvider extends APEZProvider {
#Override
public String getAuthority() {
return "com.example.extension.ZipFileContentProvider";
}
}
Get file URI:
final Uri CONTENT_URI = Uri.parse("content://" + "com.example.extension.ZipFileContentProvider");
Uri uri = Uri.parse(CONTENT_URI + "/drawable/" + name)
To create the obb file i used a gradle script (the res folder is in the same directory):
task createExpansionFile(type: Zip) {
from 'res'
entryCompression = ZipEntryCompression.STORED
archiveName = 'main' + '.' + '1' + '.' + 'com.example' + '.obb'
println archiveName
println relativePath(destinationDir)
println relativePath(archivePath)
}

Related

File.renameTo return false

I want to rename my png file. Image current path like this:
/storage/emulated/0/Android/data/sample.png
I want to save this image under app's file directory. I give write external storage permission on runtime.
File toFileDir = new File(getFilesDir() + "images");
if(toFileDir.exists()) {
File file = new File("/storage/emulated/0/Android/data/sample.png");
File toFile = new File(getFilesDir() + "images/sample-1.png");
file.renameTo(toFile);
}
renameTo returns false. But I couldn't understand the reason.
Internal and external memory is two different file systems. Therefore renameTo() fails.
You will have to copy the file and delete the original
Original answer
You can try the following method:
private void moveFile(File src, File targetDirectory) throws IOException {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (!src.renameTo(new File(targetDirectory, src.getName()))) {
// If rename fails we must do a true deep copy instead.
Path sourcePath = src.toPath();
Path targetDirPath = targetDirectory.toPath();
try {
Files.move(sourcePath, targetDirPath.resolve(sourcePath.getFileName()), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException ex) {
throw new IOException("Failed to move " + src + " to " + targetDirectory + " - " + ex.getMessage());
}
}
} else {
if (src.exists()) {
boolean renamed = src.renameTo(targetDirectory);
Log.d("TAG", "renamed: " + renamed);
}
}
}

Including files in building apk application in Unity

How to add files and folders to the apk file when building it in unity.
What I need is to have some files and a folder to be present in the parent directory of the application ( android/data/com.company.product/files) after installing it on Android.
This is my code for copying files from streaming assets into android persist path:
using System.IO;
using UnityEngine;
public static class FileManager
{
public static string RereadFile(string fileName)
{ //copies and unpacks file from apk to persistentDataPath where it can be accessed
string destinationPath = Path.Combine(Application.persistentDataPath, fileName);
#if UNITY_EDITOR
string sourcePath = Path.Combine(Application.streamingAssetsPath, fileName);
#else
string sourcePath = "jar:file://" + Application.dataPath + "!/assets/" + fileName;
#endif
//UnityEngine.Debug.Log(string.Format("{0}-{1}-{2}-{3}", sourcePath, File.GetLastWriteTimeUtc(sourcePath), File.GetLastWriteTimeUtc(destinationPath)));
//copy whatsoever
//if DB does not exist in persistent data folder (folder "Documents" on iOS) or source DB is newer then copy it
//if (!File.Exists(destinationPath) || (File.GetLastWriteTimeUtc(sourcePath) > File.GetLastWriteTimeUtc(destinationPath)))
{
if (sourcePath.Contains("://"))
{
// Android
WWW www = new WWW(sourcePath);
while (!www.isDone) {; } // Wait for download to complete - not pretty at all but easy hack for now
if (string.IsNullOrEmpty(www.error))
{
File.WriteAllBytes(destinationPath, www.bytes);
}
else
{
Debug.Log("ERROR: the file DB named " + fileName + " doesn't exist in the StreamingAssets Folder, please copy it there.");
}
}
else
{
// Mac, Windows, Iphone
//validate the existens of the DB in the original folder (folder "streamingAssets")
if (File.Exists(sourcePath))
{
//copy file - alle systems except Android
File.Copy(sourcePath, destinationPath, true);
}
else
{
Debug.Log("ERROR: the file DB named " + fileName + " doesn't exist in the StreamingAssets Folder, please copy it there.");
}
}
}
StreamReader reader = new StreamReader(destinationPath);
var jsonString = reader.ReadToEnd();
reader.Close();
return jsonString;
}
}
I hope it helps.

How to open a file without knowing its extension but knowing full name?

Intent tostart = new Intent(Intent.ACTION_VIEW);
tostart.setDataAndType(Uri.parse(video_path+".***"), "video/*");
startActivity(tostart);
Let's say I have a file path
/mnt/sdcard/video/my_birthday_moovie001
'my_birthday_moovie001' can be either .mkv, .mpg or .mkv. I've tried to add ".***" to the file path but I still can't open the file.
Well i read the comments you have stored your path in db without extensions there are many extensions that exists so android cant automatically pick the extension you have to create some way to detect extension.
following is a robust way that is best match in your case but not recommended in proper cases where extensions are known
public String chk_path(String filePath)
{
//create array of extensions
String[] ext=new String[]{".mkv",".mpg"}; //You can add more as you require
//Iterate through array and check your path which extension with your path exists
String path=null;
for(int i=0;i<ext.Length;i++)
{
File file = new File(filePath+ext[i]);
if(file.exists())
{
//if it exists then combine the extension
path=filePath+ext[i];
break;
}
}
return path;
}
now to play a song in your code
if(chk_path(video_path)!=null)
{
Intent tostart = new Intent(Intent.ACTION_VIEW);
tostart.setDataAndType(Uri.parse(video_path), "video/*");
startActivity(tostart);
}
else
//tell user that although the path in database but file on this path do not exists
Well as I put on comments
You could compare if the path matches with any filename(it doesn't contains the extension) and then if it does you got it.
You can simply do this :
Get the directory path
File extStore = Environment.getExternalStorageDirectory();
Set the file name my_birthday_moovie001 on my example I put unnamed but change it as your like
String NameOfFile = "unnamed";
Add the videos, I put it Downloads but you can change it
String PathWithFolder = extStore + "/Download/";
Create a method that lists all the files from your path
private List<String> getListFiles(File parentDir) {
ArrayList<String> inFiles = new ArrayList<String>();
File[] files = parentDir.listFiles();
for (File file : files) {
if (file.isDirectory()) {
inFiles.addAll(getListFiles(file));
} else {
String AbsolutePath = file.getAbsolutePath();
//Get the file name ex : unnamed.jpg
String nameofFile = AbsolutePath.substring(AbsolutePath.lastIndexOf("/") + 1, AbsolutePath.length());
//Remove the .jpg --> Output unnamed
String fileNameWithoutExtension = nameofFile.substring(0, nameofFile.lastIndexOf('.'));
//Add each file
inFiles.add(fileNameWithoutExtension);
}
}
return inFiles;
}
You got the names of the files doing this
List<String> files = getListFiles(new File(PathWithFolder));
Simply add a for that looks for a match of your file
for (int i = 0; i<=files.size()-1; i++){
if(PathWithFolder.equals(files.get(i))) {
Toast.makeText(MainActivity.this, "You got it!", Toast.LENGTH_SHORT).show();
}
else{
Toast.makeText(MainActivity.this, "You don't.", Toast.LENGTH_SHORT).show();
}
}
If you want to get the path as well and do what #Zain Ul Abidin proposed and compare it on getListFiles() method add this :
String fileExtension = nameofFile.substring(nameofFile.lastIndexOf("."));
Hope it helps.
From the other question :
Consider DirectoryScanner from Apache Ant:
DirectoryScanner scanner = new DirectoryScanner();
scanner.setIncludes(new String[]{"**/*.java"});
scanner.setBasedir("C:/Temp");
scanner.setCaseSensitive(false);
scanner.scan();
String[] files = scanner.getIncludedFiles();
You'll need to reference ant.jar (~ 1.3 MB for ant 1.7.1).
And then, run on files array and check
if files[i].include(yourfile)
yourfile= files[i]
You may try in this way , first getting the name of file and extension then finally compare and implement. like this :
Example file name is 04chamelon and extension is .png:
File f = new File("/mnt/storage/sdcard/Pictures/04chameleon");
File yourDir = new File("/mnt/storage/sdcard/Pictures");
nametwo = f.getName();
for (File fa : yourDir.listFiles()) {
if (fa.isFile())
fa.getName();
String path = fa.getName(); // getting name and extension
filextension = path.substring(path.lastIndexOf(".") + 1); // seperating extension
name1 = fa.getName();
int pos = name1.lastIndexOf(".");
if (pos > 0) {
name1 = name1.substring(0, pos);
}
}
if (name1.equals(nametwo)) {
Intent tostart = new Intent(Intent.ACTION_VIEW);
tostart.setDataAndType(Uri.parse(f + "." + filextension), "image/*");
//tostart.setDataAndType(Uri.parse(f + "." + filextension), "video/*");
startActivity(tostart);
}
With the latest ContentResolver, you can easily make this work using the contentResolver.getType(uri) function which detects the filetype.
private fun getIntentForFile(intent: Intent, filePath: String, context: Context): Intent {
val uri = FileProvider.getUriForFile(
context,
context.applicationContext.packageName + ".fileprovider",
File(filePath)
)
intent.putExtra(Intent.EXTRA_STREAM, uri)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.setDataAndType(uri, context.contentResolver.getType(uri))
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
return intent
}

Making Android filepaths uniform

I have three segments of code: one that sets the original filepath of the file, one that is used in renaming the file, and one that is used to match the file so that the file (audio recording) can be played.
My problem is that, to the best of my knowledge & what I have been able to find out online, I need "file://" before the rest of the filepath when I am renaming it...otherwise the MediaPlayer throws up exceptions when I try to do the playback. After much searching, I have not come up with a good way to make them uniform so that the "matcher" code can work on all the files. My best guess is that it would be ideal if I could find a way to not have to use "file://" before the rest of the filepath.
1) Code that sets original filepath:
public void setFileNameAndPath(){
int count = 0;
File f;
do{
count++;
mFileName = getString(R.string.default_file_name)
+ " #" + (mDatabase.getCount() + count) + ".mp4";
mFilePath = Environment.getExternalStorageDirectory().getAbsolutePath();
mFilePath += "/SoundRecorder/" + mFileName;
f = new File(mFilePath);
}while (f.exists() && !f.isDirectory());
}
2) Renaming the filepath:
public void rename(int position, String name) {
//rename a file
String mFilePath = "file://" + Environment.getExternalStorageDirectory().getAbsolutePath();
mFilePath += "/SoundRecorder/" + name;
File f = new File(mFilePath);
if (f.exists() && !f.isDirectory()) {
//file name is not unique, cannot rename file.
Toast.makeText(mContext,
String.format(mContext.getString(R.string.toast_file_exists), name),
Toast.LENGTH_SHORT).show();
} else {
//file name is unique, rename file
File oldFilePath = new File(getItem(position).getFilePath());
oldFilePath.renameTo(f);
mDatabase.renameItem(getItem(position), name);
notifyItemChanged(position);
}
}
3) Matching the file:
Intent iin = getIntent();
Bundle b = iin.getExtras();
newString = (String) b.get("filename");
mFilePath = Environment.getExternalStorageDirectory().getAbsolutePath();
mFilePath += "/SoundRecorder/" + newString;
I think file:// is the URI of the file and it's useful for example in a mediaplayer where the resource can exists on local storage (file://) or over internet (http://)
To "convert" string to URI use
Uri uri = Uri.parse("http://www.google.com");
And to "convert" URI to file use
File file = new File(uri.getPath());

Android mkdirs() sdcard do not work

I want to make dir in Sdcard, and i do follow:
I added: <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> in manifest.
I get root_path by: public static final String ROOT_PATH = Environment.getExternalStorageDirectory().toString() + "/Hello_World/"; and it returns
/storage/emulated/0/Hello_World (getting when debug).
Next, I run this code:
File file = new File(Constants.ROOT_PATH);
int i = 0;
while (!file.isDirectory() && !file.mkdirs()) {
file.mkdirs();
Log.e("mkdirs", "" + i++);
}
I also tried both mkdirs() and mkdir() but it's showing endless loop in logcat (Log.e("mkdirs", "" + i++);). Sometimes it work, but sometimes not.
Thanks for you helping!
Update: I tried my code for some devices: Nexus4, nexus7, Vega Iron, Genymotion, LG G Pro, then just Vega Iron work as expected. ??!!?!?
Try like this it will create a folder in the sd card
String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root + "/hello_world");
myDir.mkdirs();
If you want to check that file exists or not use this code
File file = new File (myDir, file_name);
if (file.exists ())
// file exist
else
// file not exist
For reference look at this answer Android saving file to external storage
The error is cause by && in while (!file.isDirectory() && !file.mkdirs()) it should be while (!file.isDirectory() || !file.mkdirs()). You should also check if the media is mounted.
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
{
if (DEBUG) {Log.d(TAG, "createSoundDir: media mounted");} //$NON-NLS-1$
File externalStorage = Environment.getExternalStorageDirectory();
if (externalStorage != null)
{
String externalStoragePath = externalStorage.getAbsolutePath();
File soundPathDir = new File(externalStoragePath + File.separator + "Hello_World"); //$NON-NLS-1$
if (soundPathDir.isDirectory() || soundPathDir.mkdirs())
{
String soundPath = soundPathDir.getAbsolutePath() + File.separator;
if (DEBUG) {Log.d(TAG, "soundPath = " + soundPath);} //$NON-NLS-1$
}
}
}
Cut and paste from one of my project.
Thank all you guys, finally i found out the problem. The problem is in the while() loop, I replace by
if
(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
&& !file.isDirectory()) {
file.mkdirs(); }
Use Environment.getExternalStorageDirectory().getAbsolutePath() as below...
public static final String ROOT_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Hello_World/";
And Check that SDCard is mounted before creating directory as below....
File file = new File(Constants.ROOT_PATH);
int i = 0;
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
if(!file.exists()) {
file.mkdir();
}
}

Categories

Resources