How can we set proxy in Android webview programmatically on latest Kitkat release?
This SO link WebView android proxy talks about version upto SDK version 18. But those solution no more works with Kitkat as underlying webkit implementation is changed and it uses chromium now.
Here is my solution:
public static void setKitKatWebViewProxy(Context appContext, String host, int port) {
System.setProperty("http.proxyHost", host);
System.setProperty("http.proxyPort", port + "");
System.setProperty("https.proxyHost", host);
System.setProperty("https.proxyPort", port + "");
try {
Class applictionCls = Class.forName("android.app.Application");
Field loadedApkField = applictionCls.getDeclaredField("mLoadedApk");
loadedApkField.setAccessible(true);
Object loadedApk = loadedApkField.get(appContext);
Class loadedApkCls = Class.forName("android.app.LoadedApk");
Field receiversField = loadedApkCls.getDeclaredField("mReceivers");
receiversField.setAccessible(true);
ArrayMap receivers = (ArrayMap) receiversField.get(loadedApk);
for (Object receiverMap : receivers.values()) {
for (Object rec : ((ArrayMap) receiverMap).keySet()) {
Class clazz = rec.getClass();
if (clazz.getName().contains("ProxyChangeListener")) {
Method onReceiveMethod = clazz.getDeclaredMethod("onReceive", Context.class, Intent.class);
Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
/*********** optional, may be need in future *************/
final String CLASS_NAME = "android.net.ProxyProperties";
Class cls = Class.forName(CLASS_NAME);
Constructor constructor = cls.getConstructor(String.class, Integer.TYPE, String.class);
constructor.setAccessible(true);
Object proxyProperties = constructor.newInstance(host, port, null);
intent.putExtra("proxy", (Parcelable) proxyProperties);
/*********** optional, may be need in future *************/
onReceiveMethod.invoke(rec, appContext, intent);
}
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
I hope it can help you.
Note: The Context parameter should be an Application context as the parameter name showed, you could use your own implemented Application instance which extend Application.
I've made some changes to #xjy2061's answer.
Changes are:
getDeclaredField to getField --> You use this if you declared your own application class. Else it won't find it.
Also, remember to change "com.your.application" to your own application's class canonical name.
private static boolean setKitKatWebViewProxy(WebView webView, String host, int port) {
Context appContext = webView.getContext().getApplicationContext();
System.setProperty("http.proxyHost", host);
System.setProperty("http.proxyPort", port + "");
System.setProperty("https.proxyHost", host);
System.setProperty("https.proxyPort", port + "");
try {
Class applictionCls = Class.forName("acr.browser.barebones.Jerky");
Field loadedApkField = applictionCls.getField("mLoadedApk");
loadedApkField.setAccessible(true);
Object loadedApk = loadedApkField.get(appContext);
Class loadedApkCls = Class.forName("android.app.LoadedApk");
Field receiversField = loadedApkCls.getDeclaredField("mReceivers");
receiversField.setAccessible(true);
ArrayMap receivers = (ArrayMap) receiversField.get(loadedApk);
for (Object receiverMap : receivers.values()) {
for (Object rec : ((ArrayMap) receiverMap).keySet()) {
Class clazz = rec.getClass();
if (clazz.getName().contains("ProxyChangeListener")) {
Method onReceiveMethod = clazz.getDeclaredMethod("onReceive", Context.class, Intent.class);
Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
/*********** optional, may be need in future *************/
final String CLASS_NAME = "android.net.ProxyProperties";
Class cls = Class.forName(CLASS_NAME);
Constructor constructor = cls.getConstructor(String.class, Integer.TYPE, String.class);
constructor.setAccessible(true);
Object proxyProperties = constructor.newInstance(host, port, null);
intent.putExtra("proxy", (Parcelable) proxyProperties);
/*********** optional, may be need in future *************/
onReceiveMethod.invoke(rec, appContext, intent);
}
}
}
return true;
} catch (ClassNotFoundException e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
Log.v(LOG_TAG, e.getMessage());
Log.v(LOG_TAG, exceptionAsString);
} catch (NoSuchFieldException e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
Log.v(LOG_TAG, e.getMessage());
Log.v(LOG_TAG, exceptionAsString);
} catch (IllegalAccessException e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
Log.v(LOG_TAG, e.getMessage());
Log.v(LOG_TAG, exceptionAsString);
} catch (IllegalArgumentException e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
Log.v(LOG_TAG, e.getMessage());
Log.v(LOG_TAG, exceptionAsString);
} catch (NoSuchMethodException e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
Log.v(LOG_TAG, e.getMessage());
Log.v(LOG_TAG, exceptionAsString);
} catch (InvocationTargetException e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
Log.v(LOG_TAG, e.getMessage());
Log.v(LOG_TAG, exceptionAsString);
} catch (InstantiationException e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
Log.v(LOG_TAG, e.getMessage());
Log.v(LOG_TAG, exceptionAsString);
}
return false;
}
I am creating a cordova android application, and couldn't figure out why ajax requests to internal hosts on my company's network were failing on KitKat. All native web requests succeeded, and all ajax requests on android versions below 4.4 succeeded aswell. The ajax requests only failed when on the internal company wifi which was even more perplexing.
Turns out KitKat uses a new chrome webview which is different from the standard webviews used in previous android versions. There is a bug in the version of chromium that kitkat uses where it doesn't respect the proxy exclusion list. Our company wifi sets a proxy server, and and excludes all internal hosts. The ajax requests were ultimately failing because authentication to the proxy was failing. Since these requests are to internal hosts, it should have never been going through the proxy to begin with. I was able to adapt xjy2061's answer to fit my usecase.
Hopefully this helps someone in the future and saves them a few days of head banging.
//Set KitKat proxy w/ proxy exclusion.
#TargetApi(Build.VERSION_CODES.KITKAT)
public static void setKitKatWebViewProxy(Context appContext, String host, int port, String exclusionList) {
Properties properties = System.getProperties();
properties.setProperty("http.proxyHost", host);
properties.setProperty("http.proxyPort", port + "");
properties.setProperty("https.proxyHost", host);
properties.setProperty("https.proxyPort", port + "");
properties.setProperty("http.nonProxyHosts", exclusionList);
properties.setProperty("https.nonProxyHosts", exclusionList);
try {
Class applictionCls = Class.forName("android.app.Application");
Field loadedApkField = applictionCls.getDeclaredField("mLoadedApk");
loadedApkField.setAccessible(true);
Object loadedApk = loadedApkField.get(appContext);
Class loadedApkCls = Class.forName("android.app.LoadedApk");
Field receiversField = loadedApkCls.getDeclaredField("mReceivers");
receiversField.setAccessible(true);
ArrayMap receivers = (ArrayMap) receiversField.get(loadedApk);
for (Object receiverMap : receivers.values()) {
for (Object rec : ((ArrayMap) receiverMap).keySet()) {
Class clazz = rec.getClass();
if (clazz.getName().contains("ProxyChangeListener")) {
Method onReceiveMethod = clazz.getDeclaredMethod("onReceive", Context.class, Intent.class);
Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
/*********** optional, may be need in future *************/
final String CLASS_NAME = "android.net.ProxyProperties";
Class cls = Class.forName(CLASS_NAME);
Constructor constructor = cls.getConstructor(String.class, Integer.TYPE, String.class);
constructor.setAccessible(true);
Object proxyProperties = constructor.newInstance(host, port, exclusionList);
intent.putExtra("proxy", (Parcelable) proxyProperties);
/*********** optional, may be need in future *************/
onReceiveMethod.invoke(rec, appContext, intent);
}
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
You would call the method above as follows:
First import this library at the top of your file.
import android.util.ArrayMap;
Then call the method
int currentapiVersion = android.os.Build.VERSION.SDK_INT;
//check first to see if we are running KitKat
if (currentapiVersion >= Build.VERSION_CODES.KITKAT){
setKitKatWebViewProxy(context, proxy, port, exclusionList);
}
https://android.googlesource.com/platform/external/chromium/+/android-4.4_r1/net/proxy/proxy_config_service_android.cc
Has methods to set the proxy. I am still trying to figure out how to invoke this from Java code. Pointers?
https://codereview.chromium.org/26763005
Guess from this patch, you'll be able to set up a proxy again in the near future, perhaps.
Had some issues with the provided solution on some devices when loading page from onCreate right away after setting the proxy configuration. Opening the web page after some small delay solved the problem. Seems like the proxy config needs some time to get effective.
I have a simple problem.
I want to delete a recordStore data.
when I execute the deletion code
I get this error message
javax.microedition.rms.RecordStoreException: deleteRecordStore error: record store is still open at
javax.microedition.rms.RecordStore.deleteRecordStore()
try
{
recordStore2.closeRecordStore() ;
}
catch(Exception e)
{
e.printStackTrace();
}
try
{
recordStore2.deleteRecordStore("recordStore2");
}
catch(Exception e)
{
e.printStackTrace();
}
Oh...
I have know the answer.
I should close my RecordStore into each block of code after finishing of using
it,throughout the program.
try
{
recordStore2.closeRecordStore() ;
}
catch(Exception e)
{
e.printStackTrace();
}
I am trying to send the images captured from client to server,images are captured using robot class and writing to client socket. In server i am reading the buffered image and writing into server local storage area.I want client capture the screenshots at a regular interval and send to server.server reads the images and stores in its repository.
public class ServerDemo {
public static void main(String[] args) {
try {
ServerSocket serversocket=new ServerSocket(6666);
System.out.println("server listening..........");
while(true)
{
Thread ts=new Thread( new ServerThread(serversocket.accept()));
ts.start();
System.out.println("server thread started.........");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
ServerThread.java
public class ServerThread implements Runnable {
Socket s;
BufferedImage img = null;
String savelocation="d:\\Screenshot\\";
public ServerThread(Socket server) {
this.s=server;
}
#Override
public void run() {
try {
System.out.println("trying to read Image");
img = ImageIO.read(s.getInputStream());
System.out.println("Image Reading successful.....");
} catch (IOException e) {
System.out.println(e);
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
File save_path=new File(savelocation);
save_path.mkdirs();
try {
ImageIO.write(img, "JPG",new File(savelocation+"img-"+System.currentTimeMillis()+".jpg"));
System.out.println("Image writing successful......");
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println(e);
e.printStackTrace();
}
}
}
ClientDemo.java
public class ClientDemo {
public static void main(String[] args) throws InterruptedException {
try {
Socket client=new Socket("localhost", 6666);
while(true)
{
System.out.println("Hello");
Thread th=new Thread(new ClientThread(client));
th.start();
System.out.println("Thread started........");
th.sleep(1000*60);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
ClientThread.java
public class ClientThread implements Runnable{
Socket c;
public ClientThread(Socket client) {
this.c=client;
}
#Override
public void run() {
try {
System.out.println("client");
//while(true){
Dimension size=Toolkit.getDefaultToolkit().getScreenSize();
Robot robot=new Robot();
BufferedImage img=robot.createScreenCapture(new Rectangle(size));
System.out.println("Going to capture client screen");
ImageIO.write(img, "JPG", c.getOutputStream());
System.out.println("Image capture from client success...!");
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (AWTException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Server Console
server listening..........
server thread started.........
trying to read Image
Image Reading successful.....
Image writing successful......
Client console
Hello
Thread started........
client
Going to capture client screen
Image capture from client success...!
Hello
Thread started........
client
Going to capture client screen
Hello
Thread started........
client
Going to capture client screen
Repeat like this.This code works perfectly for first time after that it fails.Each time runs it capture the images only once.What change i have to make to capture and write the images at regular intervals...Please help me
Try this in ClientDemo.java
while(true)
{
System.out.println("Hello");
Socket client=new Socket("localhost", 6666);
Thread th=new Thread(new ClientThread(client));
th.start();
System.out.println("Thread started........");
th.sleep(1000*60);
}
And make sure that you close the client socket once the thread(ClientThread.java) is completed may be in finally block or at the end of code.
You don't need ImageIO for the server end of this. Just send and receive bytes:
while ((count = in.read(buffer()) > 0)
{
out.write(buffer, 0, count);
}
I see the problem is in the server. The first time it accepts a connection from the client,Thread ts=new Thread( new ServerThread(serversocket.accept())); but the client only connects once Socket client=new Socket("localhost", 6666); When the first transfer is completed the server stay again in the accept waiting for the client to make the connect which never happen again. Therefore either you should issue only one accept and use that socket for every transfer or close both sockets, at the client and server, and make the accept/connect again.
I have tried in many different ways to send my xml document over a socket connection between a server and a client without closing the socket after sending (keep the outputstream open, for sending another document). I have found several sites who claimed that it should work, so I tried it in all the ways they sugested, but I did not found a way which works.
(that describes the same what I would like to do: http://jaxb.java.net/guide/Designing_a_client_server_protocol_in_XML.html)
The follwing code works perfectly if I am closing the socket after sending (#code marsh.marshal(element, xsw);), but it stucks on unmarshaling on the server side, if I try to keep the socket open.
Client Side....
public void sendMessage(String message){
JAXBContext jaxbContext;
try {
jaxbContext = JAXBContext.newInstance("cdl.wizard.library");
Marshaller marsh = jaxbContext.createMarshaller();
marsh.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marsh.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "http://www.example.org/WizardShema WizardsSchema.xsd");
ObjectFactory of = new ObjectFactory();
// the Dataset is the root element of the xml document
Dataset set = new Dataset("CONN01", "CONTR", "MCL01#localhost", "SV01#localhost:32000");
CommandSet cmdSet = new CommandSet();
Command cmd = new Command();
cmd.setFunctionName("RegisterAs");
Param p = new Param();
p.setString("RemoteClient");
cmd.addParameter(p);
cmdSet.addCommand(cmd);
set.setInstruction(cmdSet);
// creates a valid xml dataset, with startDocument, startElement...
JAXBElement<Dataset> element = of.createData(set);
XMLStreamWriter xsw = XMLOutputFactory.newInstance().createXMLStreamWriter(mOOS);
marsh.marshal(element, xsw);
xsw.flush();
} catch (JAXBException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (XMLStreamException e) {
e.printStackTrace();
} catch (FactoryConfigurationError e) {
e.printStackTrace();
}
SERVER Side....
private void handleMessage() {
JAXBContext jaxbContext;
try {
jaxbContext = JAXBContext.newInstance("cdl.wizard.library") ;
Unmarshaller um = jaxbContext.createUnmarshaller();
XMLInputFactory xmlif = XMLInputFactory.newInstance();
// XMLEventReader xmlr = xmlif.createXMLEventReader(mOIS);
XMLStreamReader xmlr = xmlif.createXMLStreamReader(mOIS, "UTF8");
// move to the root element and check its name.
xmlr.nextTag();
System.out.println("TagName:" + xmlr.getLocalName());
xmlr.require(START_ELEMENT, null, "Data");
JAXBElement<Dataset> obj = um.unmarshal(xmlr, Dataset.class);
Dataset set = obj.getValue();
System.out.println("ID:"+ set.getID());
} catch (JAXBException e) {
e.printStackTrace();
} catch (XMLStreamException e) {
e.printStackTrace();
} catch (FactoryConfigurationError e) {
e.printStackTrace();
}
}
I want to send a message to my computer from my phone using TCP..My computer is the server and my phone is the client. I am able to send a message from my phone to my computer but in the output, I get null characters ..
I paste my codes below;;
Client ::
public void startApp() {
try {
// establish a socket connection with remote server
streamConnection =
(StreamConnection) Connector.open(connectString);
// create DataOuputStream on top of the socket connection
outputStream = streamConnection.openOutputStream();
dataOutputStream = new DataOutputStream(outputStream);
// send the HTTP request
dataOutputStream.writeChars("Hello");
dataOutputStream.flush();
// create DataInputStream on top of the socket connection
inputStream = streamConnection.openInputStream();
dataInputStream = new DataInputStream(inputStream);
// retrieve the contents of the requested page from Web server
String test="";
int inputChar;
System.out.println("Entering read...........");
while ( (inputChar = dataInputStream.read()) != -1) {
// test=test+((char)inputShar);
results.append((char) inputChar);
}
System.out.println("Leaving read...........");
// display the page contents on the phone screen
//System.out.println(" Result are "+results.toString());
System.out.println(" ");
resultField = new StringItem(null, results.toString());
System.out.println("Client says "+resultField);
resultScreen.append(resultField);
myDisplay.setCurrent(resultScreen);
} catch (IOException e) {
System.err.println("Exception caught:" + e);
} finally {
// free up I/O streams and close the socket connection
try {
if (dataInputStream != null)
dataInputStream.close();
} catch (Exception ignored) {}
try {
if (dataOutputStream != null)
dataOutputStream.close();
} catch (Exception ignored) {}
try {
if (outputStream != null)
outputStream.close();
} catch (Exception ignored) {}
try {
if (inputStream != null)
inputStream.close();
} catch (Exception ignored) {}
try {
if (streamConnection != null)
streamConnection.close();
} catch (Exception ignored) {}
}
}
My server :
public class Main {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
try{
ServerSocket sck=new ServerSocket(880);
Socket client=sck.accept();
InputStream inp= client.getInputStream();
int i;
OutputStream out=client.getOutputStream();
out.write("Testing ".getBytes());
System.out.println("Server has responded ");
String str="";
while((i=inp.read())!=-1){
str=str+((char) i);
System.out.println("USer says "+ str);
}
}
catch(Exception e){
System.out.println("Error "+e);
}
}
}
My output for the server ;;
Server has responded
USer says null H
User says null H null
User says null H null e
etc etc
I am not supposed to get this null character,why I am getting it??
Another thing, my server is writing to the stream but the client is not able to receive that,why is that?Do I need to use a separate thread for that?
Thanks in adv
I would guess that isn't your real code, and that your real code initialized str to null.