Mon. Sep 20th, 2021

As part of FlareNetmessenger I wanted to have to ability to export a user’s wallets (and import, WIP) as a ZIP file with a password. I remembered having problems in writing to “sdcard” storage in the past with android updates.

From my first reading and experiments, the general gist seemed to be “this cannot be done” yet I managed to figure this out in a fairly short time.

We’re going to be writing an encrypted ZIP file to the Download directory of our “external” storage on android 10 (this code is also backwards compatible with prior versions of Android)

In Android 10 — and the API is probably present in older versions, too; we can’t directly access the underlying filesystem (except in a not very user-friendly way, ie in the application’s own storage directory) so instead we need to employ a ContentURI and a FileOutputStream. Example code below:

try{
    OutputStream fos;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        ContentResolver resolver = context.getContentResolver();
        ContentValues contentValues = new ContentValues();
        contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
        contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "application/zip");
        contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);
        Uri zipUri = resolver.insert(MediaStore.Downloads.getContentUri("external"), contentValues);
        fos = resolver.openOutputStream(Objects.requireNonNull(zipUri));
    } else {
        String imagesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString();
        File zipfile = new File(imagesDir, fileName);
        fos = new FileOutputStream(zipfile);
    }


    myLog("Zipper", "fos:"+fos.toString());
    JSONArray wallets = new JSONArray();
    int wC = prefs.getInt("walletCount", 0);

    for(int i = 0 ; i< wC; i++){
        wallets.put(prefs.getString("wallet"+String.valueOf(i), ""));
    }

    ZipOutputStream zout = new ZipOutputStream(fos, new ZipModel() );
    String[] filenames = new String[]{"wallets.json"};
    for (int i = 0; i < filenames.length; i++) {
        zipParameters.setFileNameInZip(filenames[0]);
        zout.putNextEntry(null, zipParameters);
        zout.write(wallets.toString().getBytes());
        zout.closeEntry();
    }
    zout.finish();
    zout.close();

This is working perfectly in our application and I hope that this provides useful information to anyone who is trying to achieve something similar. You can see the full class in FlareNetMessenger’s GitHub

By xrpdevs

Leave a Reply

Your email address will not be published. Required fields are marked *