I'm using a JavaScript interface to communicate with a JavaScript library (running in an Android webview) and the native side. This works great, except when sending over large, stringified JSON objects. It is incredibly slow, taking as long as 20 seconds. Is there a way to remedy this?
Edit: here's the JS Interface on the native side:
public class JSInterface {
private Activity activity;
public JSInterface (Activity act) {
this.activity = act;
}
public void someMethod(String message) {
try {
JSONObject obj = new JSONObject(message);
// Do stuff...
} catch (JSONException ex) {
showError(ex.getMessage());
}
}
}
And here's how the webview uses it:
$(document).ready(function() {
try {
JSInterface.someMethod(JSON.stringify(largeJsonObject));})
} catch(err) {
console.log('error: ' + err.message);
}
});
The Webview is initialized like this:
WebView mainWebView = (WebView) findViewById(R.id.activity_main_webview);
WebSettings webSettings = ProjectData.mainWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setDomStorageEnabled(true);
JSInterface mainJSInterface = new JSInterface(this);
mainWebView.addJavascriptInterface(mainJSInterface, "JSInterface");
mainWebView.setWebChromeClient(new WebChromeClient());
mainWebView.setWebViewClient(new WebViewClient());
mainWebView.loadUrl("file:///android_asset/web_view/index.html");
Related
I have viewpager and there is webview inside, the webview has swipe capability then when I swipe the webview it changes the whole viewpager, but I want if the swipe in the webview is finished then it changes the viewpager here is mycode
Pager adapter
#Override
public int getCount() {
return pageModels.size();
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view==object;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
View view = LayoutInflater.from(context).inflate(R.layout.singlepage,container,false);
webView = (WebView) view.findViewById(R.id.webview);
webView.getSettings().setJavaScriptEnabled(true);
webView.setScrollContainer(true);
webView.bringToFront();
webView.getSettings().setUseWideViewPort(true);
String readerContent = null;
File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+File.separator+"check.html");
Log.d("readerContent",readerContent);
webView.loadUrl("http://192.168.0.108/book");
webView.setWebViewClient(new WebViewClient());
((ViewPager) container).addView(view);
return view;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
((ViewPager) container).removeView((View)object);
}
public String getString(InputStream i) throws IOException {
ByteArrayOutputStream result = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = i.read(buffer)) != -1) {
result.write(buffer, 0, length);
}
return result.toString("UTF-8");
}
You need to create custom ViewPager to prevent swipe.
Second, using WebView's javascript bridge to communicate native java code.
Briefly, js code might set your ViewPager swipeable or not.
+) When you inside html page reached end of swipe, call custom js function to notify native viewpager can be swipeable.
I want to list all the files in a specific folder in my a Javascript that I use to manipulate my HTMLs.
I'm using a java method to list all the files that I to display.
Here's the the class.
public class JavaScriptInterface {
private Context context;
public JavaScriptInterface(Context current){
this.context = current;
}
#JavascriptInterface
public List<String> getFileNames(String path){
String [] files;
try {
files = context.getAssets().list(path);
ArrayList<String> testName = new ArrayList<String>();
for (String file: files) {
Log.d("File name: ", file);
file = file.replace(".js", "");
String[] fileName = file.split("_");
testName.add(fileName[1]);
}
return testName;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
Then I added this in my mainActivity
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
super.init();
setToUnstrictMode();
WebView wV = (WebView)appView.getEngine().getView();
wV.addJavascriptInterface(new JavaScriptInterface(this), "jsInterface");
// Set by <content src="index.html" /> in config.xml
wV.loadUrl(launchUrl);
}
Then I tried accessing it in my JS using this function.
var getTestNames = function(){
return window.jsInterface.getFileNames("www/js/tests");
}
Apparently, It's not working.
EDIT: I noticed that I was able to call the method, the log from the method getFileNames shows up in my logs. However, for some reasons, I could not pass it properly in a variable.
Maybe just write a simple plugin. I wrote some by myself i can approve that they are working. Use tips from official cordova documentation: https://cordova.apache.org/docs/en/latest/guide/platforms/android/plugin.html
I know that it's different approach, but at least it's a working one.
I am calling a native android function via java script loaded in a webview but is not working
Here is what i have done with WebView
paintView = (WebView) findViewById(R.id.webView1);
WebSettings Websettings = paintView.getSettings();
Websettings.setBuiltInZoomControls(true);
Websettings.setSupportZoom(true);
Websettings.setJavaScriptEnabled(true);
Websettings.setBuiltInZoomControls(true);
Websettings.setRenderPriority(RenderPriority.HIGH);
paintView.getSettings().setPluginState(PluginState.ON);
paintView.setWebChromeClient(new WebChromeClient());
final MyJavaScriptInterface myJavaScriptInterface = new MyJavaScriptInterface(this);
paintView.loadUrl("file:///android_asset/index_jQueryMobile.html");
and here is the android method
#JavascriptInterface
public void byteToImage(String base64img, String ImageName) throws IOException
{
byte[] pdfAsBytes = Base64.decode(base64img.toString(), 0);
File file = new File(Environment.getExternalStorageDirectory()+"/AndroPaint");
if(!file.exists()) {
file.mkdirs();
}
File filePath = new File(Environment.getExternalStorageDirectory()+"/AndroPaint/"+ImageName+".png");
FileOutputStream os = new FileOutputStream(filePath, true);
os.write(pdfAsBytes);
os.flush();
os.close();
}
and here is the JS function
function getImageBytes()
{
var canvas = document.getElementById('canvas');
var imageName = document.getElementById('imgName');
var imgData= canvas.toDataURL();
activity.byteToImage(imgData,imageName);
}
here is the exception
01-04 10:48:50.409: E/Web Console(15681): Uncaught ReferenceError: activity is not defined:72
You made a connection interface MyJavaScriptInterface, but you forgot to attach it to the WebView:
paintView.addJavascriptInterface(new MyJavaScriptInterface(this), "activity");
That is why you are getting activity is not defined error. activity object cannot be found by JS engine.
Here is a small tutorial on that
I made a Javascript page to generate a JSON object for read it then from Android device.
I read it with the following code
StringBuilder stringBuilder = new StringBuilder();
HttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse response = client.execute(httpGet);
StatusLine statusLine = response.getStatusLine();
int statusCode = statusLine.getStatusCode();
if (statusCode == 200){
HttpEntity entity = response.getEntity();
InputStream content = entity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(content));
String line;
while ((line = reader.readLine()) != null){
stringBuilder.append(line);
}
} else {
Log.e("JSON", "Failed to donwload file");
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
The problem is that this code returns the source code of the webpage, and the source code is the script in Javascript, not the JSON string generated after execute it.
I need the JSON string and I need use Javascript to generate the JSON string because I access to an external service.
I haven't find any solution for this. I don't care if the possible solution involves the server or the Android terminal.
Thanks.
String myresponse=Html.escapeHtml(YourStringHere);
Try this.
private class MyJavaScriptInterface {
private MyJavaScriptInterface () {
}
public void setHtml(String contentHtml) {
//here you get the content html
}
}
private WebViewClient webViewClient = new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
view.loadUrl("javascript:window.ResponseChecker.setHtml"
+ "(document.body.innerHTML);");
}
}
I have a android method which one is called from Javascript for getting the selected filepath info from phone gallery. Now i want to send the filepath name to the javascript method but if i return the filepath name from the android function then it will always return the last filepath info not the current one (May be its for callback!) or if i call any javascript method to send the file info after getting the file path then its show on debug console
like that:
05-04 22:07:50.274: ERROR/Web Console(331): ReferenceError: Can't find variable: SetImageFileName at undefined:1
And here is my Code what i have done...
public class Hello extends Activity {
/** Called when the activity is first created. */
WebView webview;
private ProgressDialog progressBar;
private static final int SELECT_PICTURE = 1;
private static final int PICK_IMAGE = 1;
private String selectedImagePath;
private String filemanagerstring;
private long siteId;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
webview = (WebView) findViewById(R.id.webview);
webview.addJavascriptInterface(new JavaScriptInterface(this), "Android");
webview.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);
webview.setWebViewClient(new HelloWebViewClient());
WebSettings webSettings = webview.getSettings();
webSettings.setSavePassword(false);
webSettings.setSaveFormData(false);
webSettings.setJavaScriptEnabled(true);
webSettings.setSupportZoom(false);
webview.loadUrl(getString(R.string.ApplicationWebURL));
}
public String getPath(Uri uri) {
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
if (cursor != null) {
// HERE YOU WILL GET A NULLPOINTER IF CURSOR IS NULL
// THIS CAN BE, IF YOU USED OI FILE MANAGER FOR PICKING THE MEDIA
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} else
return null;
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
if (resultCode == RESULT_OK) {
if (requestCode == SELECT_PICTURE) {
Uri selectedImageUri = data.getData();
String filePath = null;
try {
// OI FILE Manager
filemanagerstring = selectedImageUri.getPath();
// MEDIA GALLERY
selectedImagePath = getPath(selectedImageUri);
selectedFileName=getFileName(selectedImagePath);
if (selectedImagePath != null) {
filePath = selectedImagePath;
}
else if (filemanagerstring != null) {
filePath = filemanagerstring;
}
else {
Toast.makeText(getApplicationContext(), "Unknown path",
Toast.LENGTH_LONG).show();
Log.e("Bitmap", "Unknown path");
}
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "Internal error",
Toast.LENGTH_LONG).show();
Log.e(e.getClass().getName(), e.getMessage(), e);
}
}
}
}
final class JavaScriptInterface {
Context mContext;
JavaScriptInterface(Context c) {
mContext = c;
}
/** Show a toast from the web page */
public String ShowPhoneGallery(long sId) {
try {
siteId=sId;
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select Picture"),PICK_IMAGE);
} catch (Exception e) {
Toast.makeText(getApplicationContext(),e.getMessage(),Toast.LENGTH_LONG).show();
Log.e(e.getClass().getName(), e.getMessage(), e);
}
//Calling Javascript to return the value
webview.loadUrl("javascript:SetImageFileName('"+ selectedImagePath +"')");
return selectedImagePath;
}
}
}
I
s there anybody who can help me on this issue ...
Looks to me like you need to put this line
webview.loadUrl("javascript:SetImageFileName('"+ selectedImagePath +"')");
in a different method which is then called from onActivityResult once your user has selected the picture