2012-02-15 10 views
13

Ho avuto un problema che mi ha tormentato per giorni. Si è scoperto che si trattava di un problema tecnico Android ed è stato inviato, confermato e, si spera, verrà risolto in una versione futura. Ora ho trovato una soluzione che funziona per me e la fornirò di seguito, tuttavia la soluzione non è perfetta in quanto comporta la modifica della sorgente del gap telefonico. Principalmente la mia domanda è se qualcuno può trovare una soluzione migliore a questo problema.Problema con il caricamento di file javascript locali all'interno di una webview

The Bug:
C'è un problema tecnico quando si tenta di caricare una pagina all'interno di una WebView su Android 3.0+. Il problema è che se quella pagina fa riferimento a qualsiasi file javascript locale, non è possibile aggiungere dati di query all'URL. Fondamentalmente

Questo funziona:
<script type="text/javascript" src="StaticJS.js"></script>

Questo non funziona:
<script type="text/javascript" src="StaticJS.js?var=val"></script>

Perché diavolo qualcuno dovrebbe voler fare questo in quanto il file, ovviamente, non può fare qualsiasi cosa con i vals di query? Bene, per me ho un'applicazione per PhoneGap che carica un file di impostazioni tramite JSONP, tuttavia se un file di impostazioni non viene specificato, per impostazione predefinita è un file locale. Quindi sì, il file non può elaborare i dati della query ma sarebbe bello usare lo stesso formato di file e la stessa struttura di caricamento.


Soluzione 1 (Non-PhoneGap)

Quindi non v'è una soluzione facile a questo se la piattaforma Android di destinazione è 11 (nido d'ape) o superiore. (Fintanto che stai attento e non usi alcun metodo che non esiste in nessun livello API inferiore, questo codice verrà eseguito su 11 apis <, ma dovrai comunque impostare 11 come target)

Fondamentalmente aggiungi un WebViewClient per la WebView che utilizza il metodo shouldInterceptRequest per intercettare il caricamento di file js locali con dati di query allegati.

import java.io.IOException; 
import java.io.InputStream; 

import android.content.res.AssetManager; 
import android.webkit.WebResourceResponse; 
import android.webkit.WebView; 
import android.webkit.WebViewClient; 

public class PatchingWebViewClient extends WebViewClient{ 

    AssetManager am; 

    public PatchingWebViewClient(AssetManager am){ 
     this.am = am; 
    } 

    @Override 
    public WebResourceResponse shouldInterceptRequest (WebView view, String url){ 
     if(url.indexOf("file:///android_asset") == 0 && url.contains("?")){ 
      String filePath = url.substring(22, url.length()); 
      filePath = filePath.substring(0, filePath.indexOf("?")); 
      try { 
       InputStream is = am.open(filePath); 
       WebResourceResponse wr = new WebResourceResponse("text/javascript", "UTF-8", is); 
       return wr; 
      } catch (IOException e) { 
       return null; 
      } 
     }else{ 
      return null; 
     } 
    } 

} 

Per impostare il WebViewClient, il codice sarebbe simile a questa:

import android.app.Activity; 
import android.os.Bundle; 
import android.webkit.WebView; 

public class CanWeBreakAWebViewActivity extends Activity { 
    WebView mWebView; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 

     mWebView = (WebView) findViewById(R.id.webview); 
     mWebView.getSettings().setJavaScriptEnabled(true); 
     mWebView.setWebViewClient(new PatchingWebViewClient(this.getAssets())); 
     mWebView.loadUrl("file:///android_asset/index.html"); 
    } 
} 

Soluzione 2 (PhoneGap)

Ora, per PhoneGap non ho una soluzione pulita . La mia soluzione è quella di andare a scaricare il sorgente di PhoneGap e modificare il CordovaWebViewClient aggiungendo il seguente metodo:

@Override 
public WebResourceResponse shouldInterceptRequest (WebView view, String url){ 
    if(url.indexOf("file:///android_asset") == 0 && url.contains("?")){ 
     String filePath = url.substring(22, url.length()); 
     filePath = filePath.substring(0, filePath.indexOf("?")); 
     try { 
      InputStream is = ctx.getAssets().open(filePath); 
      WebResourceResponse wr = new WebResourceResponse("text/javascript", "Cp1252", is); 
      return wr; 
     } catch (IOException e) { 
      return null; 
     } 
    }else{ 
     return null; 
    } 
} 

Soluzione 3 (inesistente)

Questa soluzione si spera essere una facile includere classificare o modificare l'attività principale in modo da poter utilizzare il divario telefonico, ma è sufficiente utilizzare un file .jar del codice, semplificando gli aggiornamenti.

risposta

1

I dati di query vengono aggiunti ai file javascript (e ad altri tipi di file come css) per impedire la memorizzazione nella cache del browser. I dati della query sono inutili per il file, ma il browser lo considera come nuovo perché la posizione è cambiata (agli occhi del browser) e carica una nuova copia.

Sono felice che tu abbia trovato una risposta al tuo problema, ho solo pensato di dare il mio contributo sul motivo per cui le persone usano questo metodo.

+0

Il problema qui non è la memorizzazione nella cache del browser, ma il fatto che i file non vengono caricati se si aggiungono i dati della query – jtymann

+0

capito. Volevo solo dare una mano quando ho visto questa parte della tua domanda: "Perché diavolo qualcuno vorrebbe fare questo dato che ovviamente il file non può fare nulla con la query vals?" –

2

Grazie per questo post, mi hai seguito con l'ultima soluzione che è semplicemente utilizzare IceCreamCordovaWebViewClient.

@Override 
    public void init() { 
    super.init(webView, new IceCreamCordovaWebViewClient(this, webView), new CordovaChromeClient(this, webView)); 
} 
Problemi correlati