0

I want to export a csv file created in JS and let people download it on their phone.

This is my JS code for creating the file:

var createACSVFile = function () {
    var ArrayOfDataToExport = [];
    for (var k = 0; k < localStorage.length; k++) {
        console.log([localStorage.key(k),JSON.parse(localStorage.getItem(localStorage.key(k)))]);
        ArrayOfDataToExport.push([localStorage.key(k),JSON.parse(localStorage.getItem(localStorage.key(k)))])
    }


    var csvRows = [];

    for(var i=0, l=ArrayOfDataToExport.length; i<l; ++i){
        csvRows.push(ArrayOfDataToExport[i].join(','));
    }

    var csvString = csvRows.join("%0A");
    var a         = document.createElement('a');
    a.href        = 'data:attachment/csv,' + csvString;
    a.target      = '_blank';
    a.download    = 'exportFile.csv';

    document.body.appendChild(a);
    a.click();
};

createACSVFile();

This is my android code:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        view = (WebView) this.findViewById(R.id.webView);
        view.getSettings().setJavaScriptEnabled(true);
        view.getSettings().setAllowFileAccess(true);
        view.getSettings().setDomStorageEnabled(true);
        view.getSettings().setUseWideViewPort(true);
        view.getSettings().setLoadWithOverviewMode(true);
        view.setInitialScale(1);
        view.getSettings().setJavaScriptEnabled(true);
        view.getSettings().setSupportZoom(false);
        view.setWebViewClient(new MyBrowser(){

            @Override
            public void onPageFinished(WebView view, String url) {
            //hide loading image
            findViewById(R.id.imageLoading1).setVisibility(View.GONE);
            //show webview
            findViewById(R.id.webView).setVisibility(View.VISIBLE);
        }


        });
        view.loadUrl("file:///android_asset/www/index.html");
        view.setWebChromeClient(new WebChromeClient(){
});
        view.setDownloadListener(new DownloadListener() {
            public void onDownloadStart(String url, String userAgent,
                                        String contentDisposition, String mimetype,
                                        long contentLength) {
                Intent i = new Intent(Intent.ACTION_VIEW);
                i.setData(Uri.parse(url));
                startActivity(i);
            }
        });
    }

I get this error:

08-20 11:12:36.508 17111-17111/checker.coin.crypto.wingcrony.by.cryptocoinchecker E/AndroidRuntime: FATAL EXCEPTION: main Process: checker.coin.crypto.wingcrony.by.cryptocoinchecker, PID: 17111 android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=data:attachment/csv,Poloniex, currencyForToShow,usd howToOrder,Shortname passS,false whichExchangeYouUse,Bitfinex } at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1809) at android.app.Instrumentation.execStartActivity(Instrumentation.java:1523) at android.app.Activity.startActivityForResult(Activity.java:3981) at android.app.Activity.startActivityForResult(Activity.java:3933) at android.app.Activity.startActivity(Activity.java:4272) at android.app.Activity.startActivity(Activity.java:4240) at checker.coin.crypto.wingcrony.by.cryptocoinchecker.MainActivity$3.onDownloadStart(MainActivity.java:153) at com.android.webview.chromium.WebViewContentsClientAdapter.onDownloadStart(WebViewContentsClientAdapter.java:1195) at org.chromium.android_webview.AwContentsClientCallbackHelper$MyHandler.handleMessage(AwContentsClientCallbackHelper.java:126) at android.os.Handler.dispatchMessage(Handler.java:111) at android.os.Looper.loop(Looper.java:207) at android.app.ActivityThread.main(ActivityThread.java:5728) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679)

Update

If add this to my androidManifest.xml I get the same error:

<uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER"/>
Steven
  • 1,404
  • 2
  • 16
  • 39
  • Are you aware of Phonegap/Cordova which allows for hybrid apps that bridge between Javascript in webview and Java Android functionality? – Morrison Chang Aug 22 '17 at 11:48
  • Yes I know that exist. But I have created my app completly in android studio so it is impossible to change to Cordova. – Steven Aug 22 '17 at 11:49
  • I get this error: No Activity found to handle Intent { act=android.intent.action.VIEW I don't know how to fix that – Steven Aug 22 '17 at 11:50
  • Then you will have to write your own Javascript to Java bridge functions to have the Javascript code call the Java code download a file (why I suggested Cordova). DownloadManager is NOT a Intent but Java code calling a framework service: https://stackoverflow.com/questions/5877753/android-how-to-use-download-manager-class – Morrison Chang Aug 22 '17 at 11:57
  • Like you seen in the code I have an the js url but I won't work. – Steven Aug 22 '17 at 12:11
  • If you aren't familiar with Java I would *strongly* recommend looking at redoing your app in Phonegap/Cordova has a lot of features to avoid writing the bridge & native code: https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-file/index.html especially if you have do deal with platform quirks: https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-file/index.html#android-quirks – Morrison Chang Aug 22 '17 at 12:32
  • Thank you very much for information Morrison Chang I really appreciate it. I will take a look but maybe I will I will do that for an other app – Steven Aug 22 '17 at 12:35

1 Answers1

0

What I did was I generate the data I need to export to csv in the JS like this:

var generateTheDataToExportToArrayString = function () {
    var ArrayOfDataToExport = [];
    for (var k = 0; k < localStorage.length; k++) {
        var keyName = (localStorage.key(k));
        var data = JSON.parse(localStorage.getItem(localStorage.key(k)));
}
    var String = '[';
    for (var i = 0; i < ArrayOfDataToExport.length; i++){
        if (typeof ArrayOfDataToExport[i][1] === "object"){
            String += "[" + ArrayOfDataToExport[i][0] + ",";
            if (ArrayOfDataToExport[i][1].length > 1 || ArrayOfDataToExport[i][1].length === 0){
                if (ArrayOfDataToExport[i][1].length === 0){
                    String += '[' + '' + ']]';
                }
                else {
                    for (var k = 0; k < ArrayOfDataToExport[i][1].length; k++){
                        String += '[';
                        for (var l = 0; l < ArrayOfDataToExport[i][1][k].length - 1; l++){
                            String += ArrayOfDataToExport[i][1][k][l]+ ",";
                        }

                        String += ArrayOfDataToExport[i][1][k][ArrayOfDataToExport[i][1][k].length - 1] + "],";
                    }
                    String = String.slice(0, -1);
                    String += "],";
                }
            }
            else {
                String += "[";
                for (var j = 0; j < ArrayOfDataToExport[i][1].length - 2; j++){
                    String += ArrayOfDataToExport[i][1][j] + ",";
                }
                String += ArrayOfDataToExport[i][1][ArrayOfDataToExport[i][1].length - 1] + "]],";
            }
        }
        else {
            String += "[" + ArrayOfDataToExport[i][0] + ",";
            String += ArrayOfDataToExport[i][1] + "],";
        }

    }
    String = String.slice(0, -1);
    String += "]";
    console.log(String);
};

You say the last thing I do is log that string. Well that I will capture in the Java code like this:

public void onConsoleMessage(String message, int lineNumber, String sourceID) {
                if (sourceID.equals("file:///android_asset/www/assets/js/parseTest.js") && lineNumber == 184 ){
                    generateNoteOnSD(getBaseContext(),"export.csv", message);
                }
            }

This is the function generateNoteOnSD:

public void generateNoteOnSD(Context context, String sFileName, String sBody) {
        try {
            File root = new File(Environment.getExternalStorageDirectory(), "Backup_Data_For_AltFolio");
            if (!root.exists()) {
                root.mkdirs();
            }
            File gpxfile = new File(root, sFileName);
            FileWriter writer = new FileWriter(gpxfile);
            writer.append(sBody);
            writer.flush();
            writer.close();
            Toast.makeText(context, "Saved", Toast.LENGTH_SHORT).show();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
Steven
  • 1,404
  • 2
  • 16
  • 39