Übergabe von String von Webview zu JavaScript Code

  • Antworten:12
Bernd Roth
  • Forum-Beiträge: 98

27.06.2014, 23:24:30 via Website

Hallo Forum,
ich möchte gerne einen String, der ein JSON Object repräsentiert, von einer Activity zum Javascript - Code überreichen!

Hardcoded funktioniert alles innerhalb des JavaScriptes - Code, jetzt geschieht die Erzeugung der Lat / Lon Werte dynamisch.

Leider schaffe ich es nicht trotz Tutorials es hinzubekommen.

Vll. kann mir jemand weiterhelfen ( bitte nicht schlagen für den grauslichen Code! )

Danke schon einmal vielmals!

Webview:

    <script type='text/javascript'>
    function init()
    {
        var map = new L.Map ("map1");

        var attrib="";

        var layerOSM = new L.TileLayer
            ("http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
                { attribution: attrib } );

        map.addLayer(layerOSM);

        var auto = L.icon({
            iconUrl: 'auto.png',
            //shadowUrl: 'auto.png',
            iconSize:     [50, 50], // size of the icon
            //shadowSize:   [50, 64], // size of the shadow
            iconAnchor:   [100, 70], // point of the icon which will correspond to marker's location
            //shadowAnchor: [4, 62],  // the same for the shadow
            popupAnchor:  [100, 70] // point from which the popup should open relative to the iconAnchor
        });

        //map.on("click",onMapClick)
        map.on('locationfound', onLocationFound);
        map.on('locationerror', onLocationError);
        map.locate({setView: true, maxZoom: 15});

        function onMapClick(e)
        {
            // "e.latlng" is an L.LatLng object representing the mouse click position
            var clickedPosition = e.latlng;
            alert("You clicked at: " + clickedPosition.lat + " " + clickedPosition.lng);
        }
        function onLocationFound(e) {
            var radius = e.accuracy / 2;
            //L.marker(e.latlng).addTo(map).bindPopup("You are within " + radius + " meters from this point").openPopup();
            //L.circle(e.latlng, radius).addTo(map);
            L.marker(e.latlng, {icon: auto}).addTo(map);
        }
        function onLocationError(e) {
            alert(e.message);
        }

        ***var Kurzparkzonen=AndroidFunction.printLatLong();***

        L.control.scale().addTo(map);
        L.geoJson( Kurzparkzonen, {
            style: function (feature) {
                return { opacity: 0, fillOpacity: 0.5, fillColor: "#0f0" }; //Farbe: Green
            },
            onEachFeature: function(feature, layer){
                layer.bindPopup("Dauer: " + feature.properties.DAUER + " | " + "Kurzparkzone: " + feature.properties.ZEITRAUM);
            }
        }).addTo(map);

        L.geoJson( Parkstreifen, {
            style: function (feature) {
                return { opacity: 0, fillOpacity: 0.5, fillColor: "#0400ff" }; // Farbe: Blau
            },
            onEachFeature: function(feature, layer){
                layer.bindPopup("Dauer: " + feature.properties.DAUER + " | " + "Parkstreifen: " + feature.properties.ZEITRAUM);
            }
        }).addTo(map);

        L.geoJson( Parkanlage, {
            style: function (feature) {
                return { opacity: 0, fillOpacity: 0.5, fillColor: "#2b0aff" }; // Farbe: Blau
            },
            onEachFeature: function(feature, layer){
                layer.bindPopup("Dauer: " + feature.properties.OEFF_ZEITEN + " | " + "Parkanlage: " + feature.properties.PARKANLAGE);
            }
        }).addTo(map);

        L.geoJson( ParkAndRide, {
            style: function (feature) {
                return { opacity: 0, fillOpacity: 0.5, fillColor: "#f2ff7a" }; // Farbe: Gelb
            },
            onEachFeature: function(feature, layer){
                layer.bindPopup("Bezirk: " + feature.properties.BEZIRK + " | " + "Park & Ride: " + feature.properties.ADRESSE);
            }
        }).addTo(map);

    }
</script>

</head>
<body onload="init()">

            WebView browser;
        browser=(WebView)findViewById(R.id.webview1);

        WebSettings webSettings = browser.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setAppCacheEnabled(true);
        webSettings.setDatabaseEnabled(true);
        webSettings.setDomStorageEnabled(true);
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
        webSettings.setGeolocationEnabled(true);

        GeoClient geo = new GeoClient();
        browser.setWebChromeClient(geo);        
        String origin = &quot;&quot;; //how to get origin in correct format?
        geo.onGeolocationPermissionsShowPrompt(origin, this);  //obviously not how this is meant to be used but expected usage not documented
        browser.getSettings().setJavaScriptEnabled(true);
        final MyJavaScriptInterface myJavaScriptInterface = new MyJavaScriptInterface(this, message);
        browser.addJavascriptInterface(myJavaScriptInterface, &quot;AndroidFunction&quot;);


public class MyJavaScriptInterface {
    Context mContext;
    String marrayFromWebsite;

    MyJavaScriptInterface(Context c, String arrayFromWebsite) {
        mContext = c;
        marrayFromWebsite = arrayFromWebsite;
    }
    public void showToast(String toast){
        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
    }
    public void openAndroidDialog(){
        AlertDialog.Builder myDialog = new AlertDialog.Builder(WebViewActivity.this);
        myDialog.setTitle(&quot;DANGER!&quot;);
        myDialog.setMessage(&quot;You can do what you want!&quot;);
        myDialog.setPositiveButton(&quot;ON&quot;, null);
        myDialog.show();
    }
    public String printLatLong(){
        return this.marrayFromWebsite;
    }
}

lG

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

27.06.2014, 23:39:44 via Website

In die Eine Richtung (von Javascript 2 Android) geht es
http://android.programmerguru.com/how-to-bind-javascript-code-to-android-code/

Anderstherum wird es auch gehen, aber dafür muss in Javasctipt eine Funktion vorgesehen sein, die deinen String entgegenimmt:
In Android machst du es dann so;

browser.loadUrl("javascript:window.android.processHTML(deinString);";);

//Hierbei heisst das JSInterface "Android" und die Funktion die aufgerufen wird in Javascript: "Process HTML"

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Bernd Roth
  • Forum-Beiträge: 98

27.06.2014, 23:58:55 via Website

Hallo,
danke Dir vielmals!

Nun sehe ich schon einmal den String mit den JSON Objekten in der Webview.

Leider nur möchte ich nicht unbedingt den String sehen, sondern wieder meine Landkarte mit den grün markierten Zonen :)

So müsste es ja stimmen, was ich gemacht habe ( von meiner Logik her :) )
Habe es auch mit einer Funktion versucht, aber leider selbiges Ergebnis

function init(msg){
var Kurzparkzonen=msg;
}
&lt;body onload=&quot;init()&quot;&gt;

Danke Dir vielmals für Deine Hilfe!

lG

Könntest Du mir vll. nochmals helfen?

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

28.06.2014, 00:28:02 via App

Im Javascript zeigst du nirgends was an.
Dh der string sllte garnicht erschenen.
Wie seht dejn dein androidcode aus?

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Bernd Roth
  • Forum-Beiträge: 98

28.06.2014, 00:44:22 via Website

Hallo,
so sieht mein Androidcode aus

public class WebViewActivity extends Activity implements GeolocationPermissions.Callback {
/** Called when the activity is first created. */
@SuppressLint("SetJavaScriptEnabled";)
@JavascriptInterface
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.webview);

    /* Sollen Kurzparkzonen und Parkstreifen immer UpToDate sein */
    SharedPreferences prefs = this.getSharedPreferences(&quot;UpToDateWebsite&quot;, MODE_PRIVATE);
    Boolean isUpToDateWebsite = prefs.getBoolean(&quot;UpToDateWebsite&quot;, false);

    if(prefs != null &amp;&amp; isUpToDateWebsite == true)
        Log.i(&quot;Kurzparkzonen&quot;, &quot;Kurzparkzonen &amp; Parkstreifen sind gesetzt!&quot;);
    /* Sollen Kurzparkzonen und Parkstreifen immer UpToDate sein */

    LocationManager service = (LocationManager) getSystemService(LOCATION_SERVICE);
    boolean enabled = service.isProviderEnabled(LocationManager.GPS_PROVIDER);
    boolean enabled_con;
    ConnectivityManager connectivity = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    if (connectivity.getActiveNetworkInfo() != null) {
        if (connectivity.getActiveNetworkInfo().isConnected())
           enabled_con = true;
        enabled_con = false;
    }else
       enabled_con = false;

    // check if enabled and if not send user to the GSP settings
    // Better solution would be to display a dialog and suggesting to 
    // go to the settings
    if (!enabled &amp;&amp; enabled_con == false) {
        AlertDialog.Builder builder = new AlertDialog.Builder(WebViewActivity.this);
        builder.setTitle(&quot;ERROR&quot;);
        builder.setMessage(&quot;Bitte schalten Sie GPS und Datenverbindung ein!!&quot;);
        // Set up the buttons
        builder.setPositiveButton(&quot;OK&quot;, new DialogInterface.OnClickListener() { 
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
            }
        });
        builder.show();
    }else{
        String message = readFile();

// Log.d("WebViewActivity Class", message);
WebView browser;
browser=(WebView)findViewById(R.id.webview1);

        WebSettings webSettings = browser.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setAppCacheEnabled(true);
        webSettings.setDatabaseEnabled(true);
        webSettings.setDomStorageEnabled(true);
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
        webSettings.setGeolocationEnabled(true);

        GeoClient geo = new GeoClient();
        browser.setWebChromeClient(geo);        
        String origin = &quot;&quot;; //how to get origin in correct format?
        geo.onGeolocationPermissionsShowPrompt(origin, this);  //obviously not how this is meant to be used but expected usage not documented
        browser.getSettings().setJavaScriptEnabled(true);
        final MyJavaScriptInterface myJavaScriptInterface = new MyJavaScriptInterface(this, message);
        browser.addJavascriptInterface(myJavaScriptInterface, &quot;AndroidFunction&quot;);
        //browser.loadUrl(&quot;javascript:init('&quot; + message + &quot;')&quot;);
        browser.loadData(message, &quot;text/html&quot;, &quot;utf-8&quot;);
        //browser.loadUrl(&quot;file:///android_asset/index.html&quot;);
        browser.loadUrl(&quot;javascript:window.android.init(message);&quot;);
    }
}
private String readFile() {
    String ret = &quot;&quot;;

    try {
        InputStream inputStream = openFileInput(&quot;myfile&quot;);

        if ( inputStream != null ) {
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String receiveString = &quot;&quot;;
            StringBuilder stringBuilder = new StringBuilder();

            while ( (receiveString = bufferedReader.readLine()) != null ) {
                stringBuilder.append(receiveString);
            }

            inputStream.close();
            ret = stringBuilder.toString();
        }
    }
    catch (FileNotFoundException e) {
        Log.e(&quot;login activity&quot;, &quot;File not found: &quot; + e.toString());
    } catch (IOException e) {
        Log.e(&quot;login activity&quot;, &quot;Can not read file: &quot; + e.toString());
    }
    return ret;
}

public void invoke(String origin, boolean allow, boolean remember) {
}
final class GeoClient extends WebChromeClient {
    @Override
    public void onGeolocationPermissionsShowPrompt(String origin,
    Callback callback) {
        super.onGeolocationPermissionsShowPrompt(origin, callback);
        callback.invoke(origin, true, false);
    }

}

public class MyJavaScriptInterface {
    Context mContext;
    String marrayFromWebsite;

    MyJavaScriptInterface(Context c, String arrayFromWebsite) {
        mContext = c;
        marrayFromWebsite = arrayFromWebsite;
    }
    public void showToast(String toast){
        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
    }
    public void openAndroidDialog(){
        AlertDialog.Builder myDialog = new AlertDialog.Builder(WebViewActivity.this);
        myDialog.setTitle(&quot;DANGER!&quot;);
        myDialog.setMessage(&quot;You can do what you want!&quot;);
        myDialog.setPositiveButton(&quot;ON&quot;, null);
        myDialog.show();
    }
    public String printLatLong(){
        return this.marrayFromWebsite;
    }
}

}

Vorsichtshalber noch mein JavaScriptCode

        function init(msg)
    {
        var map = new L.Map (&quot;map1&quot;);

        var attrib=&quot;&quot;;

        var layerOSM = new L.TileLayer
            (&quot;http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png&quot;,
                { attribution: attrib } );

        map.addLayer(layerOSM);

        var auto = L.icon({
            iconUrl: 'auto.png',
            //shadowUrl: 'auto.png',
            iconSize:     [50, 50], // size of the icon
            //shadowSize:   [50, 64], // size of the shadow
            iconAnchor:   [100, 70], // point of the icon which will correspond to marker's location
            //shadowAnchor: [4, 62],  // the same for the shadow
            popupAnchor:  [100, 70] // point from which the popup should open relative to the iconAnchor
        });

        //map.on(&quot;click&quot;,onMapClick)
        map.on('locationfound', onLocationFound);
        map.on('locationerror', onLocationError);
        map.locate({setView: true, maxZoom: 15});

        function onMapClick(e)
        {
            // &quot;e.latlng&quot; is an L.LatLng object representing the mouse click position
            var clickedPosition = e.latlng;
            alert(&quot;You clicked at: &quot; + clickedPosition.lat + &quot; &quot; + clickedPosition.lng);
        }
        function onLocationFound(e) {
            var radius = e.accuracy / 2;
            //L.marker(e.latlng).addTo(map).bindPopup(&quot;You are within &quot; + radius + &quot; meters from this point&quot;).openPopup();
            //L.circle(e.latlng, radius).addTo(map);
            L.marker(e.latlng, {icon: auto}).addTo(map);
        }
        function onLocationError(e) {
            alert(e.message);
        } 
        var Kurzparkzonen = msg; 

        L.control.scale().addTo(map);
        L.geoJson( Kurzparkzonen, {
            style: function (feature) {
                return { opacity: 0, fillOpacity: 0.5, fillColor: &quot;#0f0&quot; }; //Farbe: Green
            },
            onEachFeature: function(feature, layer){
                layer.bindPopup(&quot;Dauer: &quot; + feature.properties.DAUER + &quot; | &quot; + &quot;Kurzparkzone: &quot; + feature.properties.ZEITRAUM);
            }
        }).addTo(map);

        L.geoJson( Parkstreifen, {
            style: function (feature) {
                return { opacity: 0, fillOpacity: 0.5, fillColor: &quot;#0400ff&quot; }; // Farbe: Blau
            },
            onEachFeature: function(feature, layer){
                layer.bindPopup(&quot;Dauer: &quot; + feature.properties.DAUER + &quot; | &quot; + &quot;Parkstreifen: &quot; + feature.properties.ZEITRAUM);
            }
        }).addTo(map);

        L.geoJson( Parkanlage, {
            style: function (feature) {
                return { opacity: 0, fillOpacity: 0.5, fillColor: &quot;#2b0aff&quot; }; // Farbe: Blau
            },
            onEachFeature: function(feature, layer){
                layer.bindPopup(&quot;Dauer: &quot; + feature.properties.OEFF_ZEITEN + &quot; | &quot; + &quot;Parkanlage: &quot; + feature.properties.PARKANLAGE);
            }
        }).addTo(map);

        L.geoJson( ParkAndRide, {
            style: function (feature) {
                return { opacity: 0, fillOpacity: 0.5, fillColor: &quot;#f2ff7a&quot; }; // Farbe: Gelb
            },
            onEachFeature: function(feature, layer){
                layer.bindPopup(&quot;Bezirk: &quot; + feature.properties.BEZIRK + &quot; | &quot; + &quot;Park &amp; Ride: &quot; + feature.properties.ADRESSE);
            }
        }).addTo(map);

    }
&lt;/script&gt;

— geändert am 28.06.2014, 01:13:58

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

28.06.2014, 08:53:46 via App

Ich würde erstmal probieren den Strig in eine Alertfunktion zu packen.

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Bernd Roth
  • Forum-Beiträge: 98

28.06.2014, 09:15:45 via Website

Ich habe es nun ein wenig erweitert und jetzt bekomme ich zumindest eine leere Webview ( nur die Aussenumrisse, keine Landkarte oder dergleichen ), aber noch keine eingezeichneten Zonen und die alert Function funktioniert auch.
Die Alert Funktion funktioniert beim Eintritt in die Funktion init(), die 2te Alert Funktion bringt hingegen undefined!

            browser.getSettings().setJavaScriptEnabled(true);
        final MyJavaScriptInterface myJavaScriptInterface = new MyJavaScriptInterface(this, message);
        browser.addJavascriptInterface(myJavaScriptInterface, &quot;AndroidFunction&quot;);
        //browser.loadUrl(&quot;javascript:init('&quot; + message + &quot;')&quot;);

        //browser.loadUrl(&quot;javascript:window.AndroidFunction.init(message);&quot;);
        //browser.loadData(message, &quot;text/html&quot;, &quot;utf-8&quot;);
        browser.setWebViewClient(new WebViewClient() 
        {

            public void onPageFinished(WebView view, String url)
            {
                browser.loadUrl(&quot;javascript:init.AndroidFunction('&quot;+message+&quot;')&quot;);
            }
        });
        browser.loadUrl(&quot;file:///android_asset/index.html&quot;);

JavaScript

        function init()
    {
    alert('test');  
    function AndroidFunction(msg){
            Kurzparkzonen = msg;
            alert(msg);
        }
        AndroidFunction(msg);

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

28.06.2014, 10:08:11 via App

Du iannst doch nicht in deienem Javascript 2Fnktionen ineinander setzen.
diese sollten getrennt sein.

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Bernd Roth
  • Forum-Beiträge: 98

28.06.2014, 10:24:07 via Website

Ich habe es nun hinbekommen!
Habe aber dabei bemerkt, dass es extremst langsam ist, vermutlich weil soviele Daten übergeben werden!?!?!
Das Ganze wird ja als String übergeben, ob es eventuell als JSON Object schneller ist?

Aber ich glaube gelesen zu haben, dass man nur einfach Objekte übergeben kann oder gibt es doch eine andere Möglichkeit noch?

Habe vorerst in meinem Programmcode onload() weggelassen, um es zu testen und konnte somit die AndroidFunction im JS aufrufen!
Die alert Funktion, welche ich getriggert habe darin, brauchte dann 1-2 Minuten um alles anzuzeigen!

Danke Dir vielmals!

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

28.06.2014, 10:29:27 via Website

War das mit den Hardcoden Strings auch so?
Welche länge Hat dein String der übergeben wird?
Vielleicht ist dieser doch zu lang, aber 2 min ist schon hefig.
Dann würde ich eher das nicht über ein Javascript Interface laufen lassen, sondern so tun als ob die Werte Hardcoded sind.
Dafür würde ich Platzhalter in die Javascript einfügen und diese dannn durch die Richtigen Strings per replace ersetzen.
Zum schluss müsstest du dann nur noch die html aus dem String laden.

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Bernd Roth
  • Forum-Beiträge: 98

28.06.2014, 10:37:18 via Website

Nein, die hardcoded Strings im JS waren alle ok.
Natürlich nur solange man ein JSON Object geladen hat.
Wenn man mehrere Kurzparkzonen, Parkflächen und co. angezeigt hat, dann wurde es sehr träge.

Aber ein JSON Object mit einer ordentlichen Länge ging noch.

Von dort lade ich mir die Werte herunter und übergebe sie dann ins JS.

http://data.wien.gv.at/daten/geo?service=WFS&amp;request=GetFeature&amp;version=1.1.0&amp;typeName=ogdwien:KURZPARKSTREIFENOGD&amp;srsName=EPSG:4326&amp;outputFormat=json

Dein Vorschlag hört sich ordentlich schwer an :)
So gut bin ich nicht in JS, dass ich das so einfach aus dem Ärmel schütteln kann, aber ich werde es mir natürlich anschauen!

Danke Dir vielmals!

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

28.06.2014, 10:50:19 via Website

So schwierig ist das nicht.

Javascript:

    &lt;script&gt;var Kurzparkzonen = null;
 Kurzparkzonen = &quot;[!Placeholder1]&quot;;
 &lt;/script&gt;

Java:

String JavaScript = getJavascript(); //Hier m&uuml;sstest du deine Vorlage in den String laden

String Parkzonen = getParkzonenJoson(); //Hier den String von deiner Seite holen

//und dann

 JavaScript = JavaScript.replace(&quot;[!Placeholder1]&quot;,Parkzonen ); //Den Javascript Platzhalter erseten

browser.loadData(JavaScript , &quot;text/html&quot;, &quot;utf-8&quot;); //Die html in den Browser laden

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Bernd Roth
  • Forum-Beiträge: 98

28.06.2014, 10:54:28 via Website

Ok, danke Dir vielmals!

Ich werde mir das einmal ansehen.

Antworten