Path to Assets?

All seems like a sledgehammer to crack a nut :wink:

Back to my original question really.

and a follow up
Why can't the file component return the path to the asset so that it can be used? It can do it for a text file using // so why not for other files?

When compiled and run on an Android 12 device

image

these blocks return:

False
/android_asset

in companion

True
/storage/emulated/0/Android/data/edu.mit.appinventor.aicompanion3/files/assets

Where do you want to use it?
Any example?

Taifun

Like so

image

The reason it works is because the core components through the various utility APIs are able to consume file://android_asset/ URIs. The APIs handle opening the resource through the AssetManager class. /android_asset/ doesn't actually exist anywhere in the file system. It is an implementation detail of the Android WebView that we have adopted as well. Generally, I would say that if you call MakeFullPath, it is better to treat the result as opaque and not try to decompose it. On iOS, the value will be different to Android. Compiled apps will return different paths than the companion. This is the nature of making a system that both allows people to test their developments in real time and compile them for later use.

1 Like

but it doesn't work for a compiled app...

you will need an if statement like this

if running in companion 
then use /storage/emulated/0/Android/data/edu.mit.appinventor.aicompanion3/files/assets
else use

EDIT: actually for the companion it is a little bit more complicated if you want to get the correct result for all Android versions and if you want it to run in Kodular as well...

       if (Build.VERSION.SDK_INT >= 29) {
         completeFileName = ApplicationSpecificDirectory() + "/assets/" + fileName;
       } else if (context.getPackageName().contains("makeroid")) {
         completeFileName =  "/storage/emulated/0/Kodular/assets/" + fileName;                
       } else {
         completeFileName = ApplicationSpecificDirectory() + "/AppInventor/assets/" + fileName; 
       }

to get the ApplicationSpecificDirectory see here

Taifun

1 Like

Yes, exactly whatI said in post #7.

Thanks people.

I do not have a problem with accessing assets when in development/companion mode. The issue arises when an app is compiled, assets can no longer be accessed by a "file path".

@Taifun, in your File extension, you can return the files in assets, hence there must be a pathway to return these filenames ? I understand it would have to be done in code and returned as a block in an extension.

As an alternative, how about getting the inputStream of an asset and saving it to a tempFile, using that to load into the pdfViewer, then deleting said file after use ? Something like:

@SimpleFunction(description = "")
  public String GetAsset(String filename) throws IOException {

    String basename = filename.split(".")[0];
    String extn = "." + filename.split(".")[1];
    File file = File.createTempFile(basename,extn);
    filePath = file.getAbsolutePath();

    InputStream in = form.openAsset(filename);
    OutputStream out = new FileOutputStream(filePath);

    //...
    
    return filePath;
  }

Yeah that is a good idea.

hmmmm, I am getting:

Runtime error: length = 0; index=0

from:

@SimpleFunction(description = "returns asset from a temporary File")
  public String GetAsset(String filename) throws IOException {

    String basename = filename.split(".")[0];
    String extn = "." + filename.split(".")[1];
    File file = File.createTempFile(basename,extn);
    filePath = file.getAbsolutePath();

    InputStream in = form.openAsset(filename);
    int size = in.available();
    byte[] buffer = new byte[size];
    in.read(buffer);
    in.close();

    FileOutputStream out = new FileOutputStream(filePath);
    out.write(buffer);
    out.close();

    return filePath;
  }

Cracked it :slight_smile:

@SimpleFunction(description = "returns asset from a temporary File")
  public String GetAsset(String filename) throws IOException {
    
    File file = File.createTempFile("temp",".pdf");
    filePath = file.getAbsolutePath();

    InputStream in = context.getAssets().open(filename);
    int size = in.available();
    byte[] buffer = new byte[size];
    in.read(buffer);
    in.close();

    FileOutputStream out = new FileOutputStream(filePath);
    out.write(buffer);
    out.close();

    return filePath;
  }

This only works with compiled app

3 Likes
return Build.VERSION.SDK_INT > 28 ? this.context.getExternalFilesDir(null).getAbsolutePath() + "/assets/" : getExternalStoragePath() + "/AppInventor/assets/";
1 Like

for development purposes

1 Like

2 Likes

couldn't get this to work for a pdf base64 string:

image

Just a blank page. I didn't use the Base64.URL_SAFE flag, but the webviewer displays image files as base64 OK?

@TIMAI2 any advances on accessing Assets in a compiled app? I also can't access files in a compiled app through /storage/emulated/0/Android/data/<package_path>/files/ (also tried with .../files/assets/). Works with AICompanion, but not in a compiled app.

There is an addon extension for this:

https://metricrat-hosting.web.app/#7