0

I want to dynamically load and interact with SVG image into Android WebView using javascript and HTML5. The below is the html source code

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="obj_idset.js"></script>
<script type="text/javascript" src="global.js"></script>
<script type="text/javascript" src="map_zoom_pan_effects.js"></script>
<script type="text/javascript" src="client-menu_position.js"></script>
<script type="text/javascript" src="client-menu_routing.js"></script>
<script type="text/javascript" src="obj_positionpoint.js"></script>
<script type="text/javascript" src="obj_borderline.js"></script>
<script type="text/javascript" src="obj_borderpoint.js"></script>
<script type="text/javascript" src="obj_edge.js"></script>
<script type="text/javascript" src="obj_polygon.js"></script>
<script type="text/javascript" src="obj_stepmarker.js"></script>
<script type="text/javascript" src="obj_vertex.js"></script>
<script type="text/javascript" src="obj_category.js"></script>
<script type="text/javascript" src="obj_gpsmarker.js"></script>
<script type="text/javascript" src="menu_import.js"></script>
<script type="text/javascript" src="routing.js"></script>
<script type="text/javascript" src="affiliation_match.js"></script>
<script type="text/javascript" src="android.js"></script>
<script type="text/javascript" src="interface.js"></script>
<script type="text/javascript" src="demowalk.js"></script>
<script type="text/javascript" src="convertCoordinates.js"></script>    
<script>
    $("embed").ready(function() {
        // Replaces onload () for initialization may take place only after the DOM has been built completely.
        console.log('version 24');
        //G.loadMaps(false);
        G.init();
        G.loadMaps(0);
        console.log("???");

    });
</script>

</head>    
<body>

        <div id="location"></div>
          <!-- Inside this div the map will be rendered -->
        <div id="map_container"></div>

    <!--        <div id="page-wrapper">

        <h1>Text File Reader</h1>
        <div>
            Select a text file: 
            <input type="file" id="fileInput">
        </div>
        <pre id="fileDisplayArea"><pre>

    </div>
    -->

     <div id="mainmenu">
          <p>Set the position</p>
          <!-- <button onclick="menu('top');">top</button> -->
          <button onclick="Interface.position_setSVG (125,125,0);">Set postion</button>

        </div>
</body>   

</html>

As above html script, the html web page includes a render SVG map which is dynamically load into element and a "Set position" button as below in desktop Chrome.

the Chrome screen shot

Now I want to display the same in Android WebView (all java script files and svg files are placed in Android assests folder). The below is Android code in main Fragment

/**
 * A placeholder fragment containing a simple view.
 */

public static class PlaceholderFragment extends Fragment {

    private SvgWebView mWebView;        
    private Button positionBtn;
    private Button destinationBtn;
    private Button routingBtn;
    private Button clearBtn;


    public PlaceholderFragment() {
    }

    @Override
    @SuppressLint({ "JavascriptInterface", "SetJavaScriptEnabled" })
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_main, container,
                false);         

        mWebView = new SvgWebView((WebView) rootView.findViewById(R.id.webView1));


        mWebView.getSettings().setJavaScriptEnabled(true);

        mWebView.getSettings().setBuiltInZoomControls(false);

        mWebView.getSettings().setUseWideViewPort(true);
        mWebView.getSettings().setSupportZoom(true);
        mWebView.getWebView().setInitialScale(0);

        mWebView.getWebView().setWebChromeClient(new WebChromeClient());

        // http://stackoverflow.com/questions/2378800/clicking-urls-opens-default-browser
        mWebView.getWebView().setWebViewClient(new WebViewClient(){
             @Override
                public boolean shouldOverrideUrlLoading(WebView view, String url) {
                    view.loadUrl(url);
                    return true;
                }
        });     

        CustomJavaScriptHandler js = new CustomJavaScriptHandler(getActivity());
        mWebView.getWebView().addJavascriptInterface(js, "svgapp");

        js.addInstructor(new CustomJavaScriptHandler.JSInstructor() {
            @Override
            public void jsinstruct(String s) {
                String parts[] = s.split(":");
                if (parts[0].equals("position")) {
                    //nodeSelected(Integer.valueOf(parts[1]));
                }
            }
        });

        CopyFilesAsyncTask copyTask = new CopyFilesAsyncTask();
        copyTask.execute();         

        positionBtn = (Button) rootView.findViewById(R.id.positionBtn);
        positionBtn.setOnClickListener(new OnClickListener(){
            @Override
            public void onClick(View v) {                   
                mWebView.svgPositionBySvg(100.0, 200.0, 0);
            }

        });

        destinationBtn = (Button) rootView.findViewById(R.id.destinationBtn);
        routingBtn = (Button) rootView.findViewById(R.id.routingBtn);
        clearBtn = (Button) rootView.findViewById(R.id.clearBtn);           

        return rootView;
    }

    /* the function is called after copying files from assest folder to external device */
    public void copyFinished() {
        try {
            Toast.makeText(getActivity(), "Copy done", Toast.LENGTH_LONG).show();
            String htmlPath = Utils.getSdDir(Utils.SVG_MAP_DATA_EXT_FOLDER).toURI().toURL().toString() + File.separator + Utils.ANDROID_HTML;
            // load the android.html 
            mWebView.loadUrl(htmlPath);

        } catch (MalformedURLException e) {

            Log.e(TAG, "Error ", e);
        }
    }

    class CopyFilesAsyncTask extends AsyncTask<Void, Void, Void> {

        public CopyFilesAsyncTask() {

        }

        @Override
        protected Void doInBackground(Void... arg0) {
            AssetManager assetManager = getActivity().getAssets();
            copyAssestsToExtDir(assetManager, Utils.SVG_MAP_DATA_ASSEST_FOLDER);                
            return null;
        }

        @Override
        protected void onPostExecute(Void arg0) {   
            copyFinished();
        }           

    }

    /* copy files in assest to external dir when the application start */   
    private void copyAssestsToExtDir(AssetManager assetManager, String subfolder) {

        String[] files = null;
        try {
            files = assetManager.list(subfolder);
        } catch (IOException e) {
            Log.e(TAG, "Failed to get asset file list.", e);
        }
        for(String filename : files) {
            Log.i(TAG, "File: " + filename);

            // this is file, hence copy
            InputStream instr = null;
            OutputStream outstr = null;
            try {
                instr = assetManager.open(subfolder + File.separator + filename);
                File out_dir = Utils.getSdDir(Utils.SVG_MAP_DATA_EXT_FOLDER); 
                File outFile = new File(out_dir, filename);
                outstr = new FileOutputStream(outFile);
                byte[] buffer = new byte[1024];
                int read;
                while ((read = instr.read(buffer)) != -1) {
                    outstr.write(buffer, 0, read);
                }
                outstr.flush();
                instr.close();          
                outstr.close();
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }

        }
    }
}   

The thing is that when running in Android, the WebView does not load svg image into its element. It calls default Android Web Browser to display the svg image as below pictures

the application WebView screen shot Android web browser is called to display SVG

As above pictures, the WebView only display the "Set postion" button, it call Android web Browser to display SVG. Hence, I could not interact with loaded SVG because SVG does not include any javascript itself (javascript files are embeded into html file not svg).

Am I missing something? Could anyone give me the solution to solve this problem?

Richard Le
  • 639
  • 2
  • 9
  • 20
  • Where is the code line to load the html in the webview? Fro whete comes that page? – greenapps Jul 12 '14 at 08:24
  • @greenapps: I edited my post which code load android.html file. All html and javascript files are placed in assest folder and they are copoed to external folder when the application start. webview load html and javascript in external storage. – Richard Le Jul 12 '14 at 08:50
  • I thought that the svg would display at load of the html. But now i'm starting to think that also in chrome a button has to be clicked/pressed by the user. You post lacks this info. – greenapps Jul 12 '14 at 09:22
  • Is it done by G.loadMaps() at load done? – greenapps Jul 12 '14 at 09:33
  • I insert "Set position" button to check whether the svg is loaded into android.html or not. If it is loaded in android.html, it must be displayed along with "Set position" button. But you see that, there is no svg image loaded, only "Set position" button. The svg is loaded in Android web browser itself. – Richard Le Jul 12 '14 at 10:56
  • @greenapps: yes, G.loadMaps() is used to load the svg image. The chrome desktop displays successfully. – Richard Le Jul 12 '14 at 10:57
  • So you say that the map is created when the page loads. Ok. But still i do not understand the scenario as you speak in different terms then my questions. I got no answer on: `I thought that the svg would display at load of the html. But now i'm starting to think that also in chrome a button has to be clicked/pressed by the user.`. Can you confirm that? – greenapps Jul 12 '14 at 11:18
  • The map is displayed when the page loads. – Richard Le Jul 12 '14 at 11:21
  • Ok. And when does it display in android browser? Upon load in webview? Whenn the user clicks the button? – greenapps Jul 12 '14 at 11:24
  • I prefer using comments here. – greenapps Jul 12 '14 at 12:29
  • @greenapps: As I mentioned, when is desktop, after the map is loaded, user can click to "Set position" add the current position point in the map But in the Android device, only button is displayed, the svg is displayed in Android web browser, user could not click set position button to add current point to the map I do not know my answer matches your question or not? – Richard Le Jul 13 '14 at 05:41

1 Answers1

0

The problem is Android 4.4 KitKat. If the above application run on 4.2 or below, it works well. But if running in 4.4, Android will call Android browser to display the embed svg image. Due to some security feature, KitKat does not allow to load file stored in internal device. You must place the file on a external server.

Richard Le
  • 639
  • 2
  • 9
  • 20