diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..c6cbe562 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 00000000..a6b6e358 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +OkHttpDemo \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 00000000..96cc43ef --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 00000000..e7bedf33 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 00000000..97626ba4 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 00000000..f7bfd9b0 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..8f8b72dc --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.8 + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..6849553c --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 00000000..7f68460d --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..6564d52d --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 00000000..8f840f2f --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,26 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 23 + buildToolsVersion "23.0.2" + + defaultConfig { + applicationId "com.lzy.okhttpdemo" + minSdkVersion 16 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(include: ['*.jar'], dir: 'libs') + compile 'com.android.support:appcompat-v7:23.1.1' + compile project(':library_okhttputils') +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 00000000..f727142b --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in E:\Android\SDK/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..d3ba1683 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/assets/srca.cer b/app/src/main/assets/srca.cer new file mode 100644 index 00000000..9f051aff Binary files /dev/null and b/app/src/main/assets/srca.cer differ diff --git a/app/src/main/assets/zhy_client.bks b/app/src/main/assets/zhy_client.bks new file mode 100644 index 00000000..a45133a8 Binary files /dev/null and b/app/src/main/assets/zhy_client.bks differ diff --git a/app/src/main/assets/zhy_server.cer b/app/src/main/assets/zhy_server.cer new file mode 100644 index 00000000..7c2b0c09 Binary files /dev/null and b/app/src/main/assets/zhy_server.cer differ diff --git a/app/src/main/java/com/lzy/okhttpdemo/Bean.java b/app/src/main/java/com/lzy/okhttpdemo/Bean.java new file mode 100644 index 00000000..0248e488 --- /dev/null +++ b/app/src/main/java/com/lzy/okhttpdemo/Bean.java @@ -0,0 +1,39 @@ +package com.lzy.okhttpdemo; + +/** + * ================================================ + * 作 者:廖子尧 + * 版 本:1.0 + * 创建日期:2016/1/14 + * 描 述: + * 修订历史: + * ================================================ + */ +public class Bean { + public String ip; + public String host; + public String port; + public String connection; + public String aaa; + public String bbb; + public String ccc; + public String xxx; + public String yyy; + public String zzz; + + @Override + public String toString() { + return "Bean{" + + "ip='" + ip + '\'' + + ", host='" + host + '\'' + + ", port='" + port + '\'' + + ", connection='" + connection + '\'' + + ", aaa='" + aaa + '\'' + + ", bbb='" + bbb + '\'' + + ", ccc='" + ccc + '\'' + + ", xxx='" + xxx + '\'' + + ", yyy='" + yyy + '\'' + + ", zzz='" + zzz + '\'' + + '}'; + } +} diff --git a/app/src/main/java/com/lzy/okhttpdemo/GApp.java b/app/src/main/java/com/lzy/okhttpdemo/GApp.java new file mode 100644 index 00000000..7080d0b4 --- /dev/null +++ b/app/src/main/java/com/lzy/okhttpdemo/GApp.java @@ -0,0 +1,54 @@ +package com.lzy.okhttpdemo; + +import android.app.Application; + +import com.lzy.okhttputils.OkHttpUtils; + +import okio.Buffer; + +/** + * ================================================ + * 作 者:廖子尧 + * 版 本:1.0 + * 创建日期:2015/9/23 + * 描 述: + * 修订历史: + * ================================================ + */ +public class GApp extends Application { + + private static final String CER_12306 = "-----BEGIN CERTIFICATE-----\n" + + "MIICmjCCAgOgAwIBAgIIbyZr5/jKH6QwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ04xKTAn\n" + + "BgNVBAoTIFNpbm9yYWlsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRTUkNBMB4X\n" + + "DTA5MDUyNTA2NTYwMFoXDTI5MDUyMDA2NTYwMFowRzELMAkGA1UEBhMCQ04xKTAnBgNVBAoTIFNp\n" + + "bm9yYWlsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRTUkNBMIGfMA0GCSqGSIb3\n" + + "DQEBAQUAA4GNADCBiQKBgQDMpbNeb34p0GvLkZ6t72/OOba4mX2K/eZRWFfnuk8e5jKDH+9BgCb2\n" + + "9bSotqPqTbxXWPxIOz8EjyUO3bfR5pQ8ovNTOlks2rS5BdMhoi4sUjCKi5ELiqtyww/XgY5iFqv6\n" + + "D4Pw9QvOUcdRVSbPWo1DwMmH75It6pk/rARIFHEjWwIDAQABo4GOMIGLMB8GA1UdIwQYMBaAFHle\n" + + "tne34lKDQ+3HUYhMY4UsAENYMAwGA1UdEwQFMAMBAf8wLgYDVR0fBCcwJTAjoCGgH4YdaHR0cDov\n" + + "LzE5Mi4xNjguOS4xNDkvY3JsMS5jcmwwCwYDVR0PBAQDAgH+MB0GA1UdDgQWBBR5XrZ3t+JSg0Pt\n" + + "x1GITGOFLABDWDANBgkqhkiG9w0BAQUFAAOBgQDGrAm2U/of1LbOnG2bnnQtgcVaBXiVJF8LKPaV\n" + + "23XQ96HU8xfgSZMJS6U00WHAI7zp0q208RSUft9wDq9ee///VOhzR6Tebg9QfyPSohkBrhXQenvQ\n" + + "og555S+C3eJAAVeNCTeMS3N/M5hzBRJAoffn3qoYdAO1Q8bTguOi+2849A==\n" + + "-----END CERTIFICATE-----"; + + @Override + public void onCreate() { + super.onCreate(); + + System.setProperty("http.proxyHost", "192.168.1.111"); + System.setProperty("http.proxyPort", "8888"); + + OkHttpUtils.debug(true, "MyOkHttp"); + try { + OkHttpUtils.getInstance()// + .setConnectTimeout(OkHttpUtils.DEFAULT_MILLISECONDS)// + .setReadTimeOut(OkHttpUtils.DEFAULT_MILLISECONDS)// +// .setCertificates(getAssets().open("srca.cer"), getAssets().open("zhy_server"))// + .setCertificates(new Buffer().writeUtf8(CER_12306).inputStream())// + .setWriteTimeOut(OkHttpUtils.DEFAULT_MILLISECONDS); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/app/src/main/java/com/lzy/okhttpdemo/MainActivity.java b/app/src/main/java/com/lzy/okhttpdemo/MainActivity.java new file mode 100644 index 00000000..53aae9fd --- /dev/null +++ b/app/src/main/java/com/lzy/okhttpdemo/MainActivity.java @@ -0,0 +1,203 @@ +package com.lzy.okhttpdemo; + +import android.os.Bundle; +import android.os.Environment; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ListView; + +import com.lzy.okhttpdemo.callback.MyBeanCallBack; +import com.lzy.okhttpdemo.callback.MyFileCallBack; +import com.lzy.okhttputils.OkHttpUtils; +import com.lzy.okhttputils.request.PostRequest; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import okhttp3.Call; +import okhttp3.MediaType; +import okhttp3.MultipartBody; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener { + + private ArrayList strings; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + strings = new ArrayList<>(); + strings.add("get"); + strings.add("post"); + strings.add("getJson"); + strings.add("postString"); + strings.add("responseJson"); + strings.add("responseJsonArray"); + strings.add("uploadFile"); + strings.add("downloadFile"); + + ListView listView = (ListView) findViewById(R.id.listView); + listView.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, strings)); + listView.setOnItemClickListener(this); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + OkHttpUtils.getInstance().cancelTag(this); + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + Class clazz = this.getClass(); + Method[] methods = clazz.getDeclaredMethods(); + for (Method method : methods) { + if (method.getName().equals(strings.get(position))) { + try { + method.invoke(this); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + } + } + + private void getJson() { + OkHttpUtils.get("http://192.168.1.111:8080/UploadServer/ResponseJson")// + .tag(this)// + .params("ppppppp", "ppp")// + .headers("hhhhhhh", "hhh")// + .execute(new MyBeanCallBack() { + @Override + public void onResponse(Bean bean) { + System.out.println("onResponse:" + bean); + } + }); + } + + private void postString() { + OkHttpUtils.post("http://192.168.1.111:8080/UploadServer/UploadString")// + .tag(this)// + .params("ppppppp", "ppp")// + .headers("hhhhhhh", "hhh")// + .content("asdfasdfasdfasdfweasd速度阿斯蒂芬阿斯蒂芬阿斯蒂芬奥赛大三asd asdf asd as")// + .mediaType(PostRequest.MEDIA_TYPE_PLAIN)// + .execute(new MyBeanCallBack() { + @Override + public void onResponse(String s) { + System.out.println("onResponse:" + s); + } + }); + } + + private void responseJson() { + OkHttpUtils.post("http://192.168.1.111:8080/UploadServer/ResponseJson")// + .tag(this)// + .params("ppppppp", "ppp")// + .headers("hhhhhhh", "hhh")// + .execute(new MyBeanCallBack() { + @Override + public void onResponse(Bean bean) { + System.out.println("onResponse:" + bean); + } + }); + } + + private void responseJsonArray() { + OkHttpUtils.post("http://192.168.1.111:8080/UploadServer/ResponseJsonArray")// + .tag(this)// + .params("ppppppp", "ppp")// + .headers("hhhhhhh", "hhh")// + .execute(new MyBeanCallBack>() { + @Override + public void onResponse(List beans) { + System.out.println("onResponse:" + beans); + } + }); + } + + private void uploadFile() { + OkHttpUtils.post("http://192.168.1.111:8080/UploadServer/UploadFile")// + .tag(this)// + .params("file1", new File(Environment.getExternalStorageDirectory() + "/DCIM/Camera/IMG_20151225_155549.jpg"))// + .params("file3", new File(Environment.getExternalStorageDirectory() + "/DCIM/Camera/IMG_20160109_010308.jpg"))// + .params("file2", new File(Environment.getExternalStorageDirectory() + "/video/splash.avi"))// + .execute(new MyBeanCallBack() { + @Override + public void onResponse(String s) { + System.out.println("onResponse:" + s); + } + }); + } + + private void downloadFile() { + OkHttpUtils.post("http://192.168.1.111:8080/UploadServer/DownloadFile")// + .tag(this)// + .params("ppppppp", "ppp")// + .headers("hhhhhhh", "hhh")// + .execute(new MyFileCallBack(Environment.getExternalStorageDirectory() + "/video", "bbb.avi") { + @Override + public void onResponse(File response) { + System.out.println("onResponse:" + response); + } + }); + } + + /** 原生方法调用 */ + private void post() { + File file1 = new File(Environment.getExternalStorageDirectory() + "/DCIM/Camera/IMG_20151225_155549.jpg"); + RequestBody filebody = RequestBody.create(MediaType.parse("application/octet-stream"), file1); + File file2 = new File(Environment.getExternalStorageDirectory() + "/video/splash.avi"); + RequestBody videobody = RequestBody.create(MediaType.parse("application/octet-stream"), file2); + + OkHttpClient client = new OkHttpClient(); + MultipartBody requestBody = new MultipartBody.Builder()// + .addFormDataPart("aaa", "111")// + .addFormDataPart("ccc", "222.jpg", filebody)// + .addFormDataPart("ggg", "666.avi", videobody).build(); + Request request = new Request.Builder().post(requestBody).url("http://192.168.1.111:8080/UploadServer/UploadFile").build(); + Call call = client.newCall(request); + call.enqueue(new okhttp3.Callback() { + @Override + public void onFailure(Request request, IOException e) { + e.printStackTrace(); + } + + @Override + public void onResponse(Response response) throws IOException { + System.out.println("-----" + response.body().string()); + } + }); + } + + /** 原生方法调用 */ + private void get() { + OkHttpClient client = new OkHttpClient(); + Request request = new Request.Builder().get().url("http://192.168.1.111:8080/UploadServer/ResponseJson").build(); + Call call = client.newCall(request); + call.enqueue(new okhttp3.Callback() { + @Override + public void onFailure(Request request, IOException e) { + e.printStackTrace(); + } + + @Override + public void onResponse(Response response) throws IOException { + System.out.println("-----" + response.body().string()); + } + }); + } +} diff --git a/app/src/main/java/com/lzy/okhttpdemo/callback/CallBack.java b/app/src/main/java/com/lzy/okhttpdemo/callback/CallBack.java new file mode 100644 index 00000000..b2a6f26f --- /dev/null +++ b/app/src/main/java/com/lzy/okhttpdemo/callback/CallBack.java @@ -0,0 +1,58 @@ +package com.lzy.okhttpdemo.callback; + +import com.google.gson.Gson; +import com.lzy.okhttputils.L; +import com.lzy.okhttputils.callback.AbsCallback; + +import org.json.JSONObject; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +import okhttp3.Response; + +/** + * ================================================ + * 作 者:廖子尧 + * 版 本:1.0 + * 创建日期:2016/1/14 + * 描 述:默认将返回的数据解析成需要的Bean + * 修订历史: + * ================================================ + */ +public abstract class CallBack extends AbsCallback { + + @Override + public T parseNetworkResponse(Response response) throws Exception { + String data = response.body().string(); + L.i("请求网络返回数据: ------ " + data); + JSONObject jsonObject = new JSONObject(data); + boolean success = false; + String resultMsg = ""; + String code = jsonObject.optString("code", null); + if ("0".equals(code)) { + success = true; //请求数据成功 + } else if ("104".equals(code)) { + resultMsg = "用户授权信息无效"; + } else if ("105".equals(code)) { + resultMsg = "用户收取信息已过期"; + } else if ("106".equals(code)) { + resultMsg = "用户账户被禁用"; + } else { + resultMsg = "错误代码:" + code + ",错误信息:" + jsonObject.optString("message", null); + } + if (success) { + Type type = this.getClass().getGenericSuperclass(); + if (type instanceof ParameterizedType) { + //如果用户写了泛型,就会进入这里,否者不会执行 + ParameterizedType parameterizedType = (ParameterizedType) type; + Class beanClass = (Class) parameterizedType.getActualTypeArguments()[0]; + Gson gson = new Gson(); + return (T) gson.fromJson(response.body().string(), beanClass); + } + } else { + L.i(resultMsg); + } + return (T) response; + } +} diff --git a/app/src/main/java/com/lzy/okhttpdemo/callback/MyBeanCallBack.java b/app/src/main/java/com/lzy/okhttpdemo/callback/MyBeanCallBack.java new file mode 100644 index 00000000..25ce83f9 --- /dev/null +++ b/app/src/main/java/com/lzy/okhttpdemo/callback/MyBeanCallBack.java @@ -0,0 +1,59 @@ +package com.lzy.okhttpdemo.callback; + +import android.support.annotation.Nullable; + +import com.lzy.okhttputils.callback.BeanCallBack; +import com.lzy.okhttputils.request.BaseRequest; + +import okhttp3.Request; +import okhttp3.Response; + +/** + * ================================================ + * 作 者:廖子尧 + * 版 本:1.0 + * 创建日期:2016/1/14 + * 描 述:默认将返回的数据解析成需要的Bean,可以是 Bean,String,List,Map + * 修订历史: + * ================================================ + */ +public abstract class MyBeanCallBack extends BeanCallBack { + + @Override + public T parseNetworkResponse(Response response) throws Exception { + System.out.println("parseNetworkResponse"); + return super.parseNetworkResponse(response); + } + + @Override + public void onAfter(@Nullable T t, Request request, Response response, @Nullable Exception e) { + System.out.println("onAfter"); + } + + @Override + public void upProgress(long currentSize, long totalSize, float progress) { + System.out.println("upProgress -- " + totalSize + " " + currentSize + " " + progress); + } + + @Override + public void downloadProgress(long currentSize, long totalSize, float progress) { + System.out.println("downloadProgress -- " + totalSize + " " + currentSize + " " + progress); + } + + @Override + public void onError(Request request, @Nullable Response response, @Nullable Exception e) { + System.out.println("onError"); + super.onError(request, response, e); + } + + @Override + public void onBefore(BaseRequest request) { + System.out.println("onBefore"); + request.params("aaa", "111")// + .params("bbb", "222")// + .params("ccc", "333")// + .headers("xxx", "444")// + .headers("yyy", "555")// + .headers("zzz", "666"); + } +} diff --git a/app/src/main/java/com/lzy/okhttpdemo/callback/MyFileCallBack.java b/app/src/main/java/com/lzy/okhttpdemo/callback/MyFileCallBack.java new file mode 100644 index 00000000..31f451a3 --- /dev/null +++ b/app/src/main/java/com/lzy/okhttpdemo/callback/MyFileCallBack.java @@ -0,0 +1,66 @@ +package com.lzy.okhttpdemo.callback; + +import android.support.annotation.Nullable; + +import com.lzy.okhttputils.callback.FileCallBack; +import com.lzy.okhttputils.request.BaseRequest; + +import java.io.File; +import java.io.IOException; + +import okhttp3.Request; +import okhttp3.Response; + +/** + * ================================================ + * 作 者:廖子尧 + * 版 本:1.0 + * 创建日期:2016/1/15 + * 描 述: + * 修订历史: + * ================================================ + */ +public abstract class MyFileCallBack extends FileCallBack { + + public MyFileCallBack(String destFileDir, String destFileName) { + super(destFileDir, destFileName); + } + + @Override + public File parseNetworkResponse(Response response) throws Exception { + System.out.println("parseNetworkResponse"); + return super.parseNetworkResponse(response); + } + + @Override + public void onBefore(BaseRequest request) { + System.out.println("onBefore"); + request.params("aaa", "111")// + .params("bbb", "222")// + .params("ccc", "333")// + .headers("xxx", "444")// + .headers("yyy", "555")// + .headers("zzz", "666"); + } + + @Override + public void onAfter(@Nullable File file, Request request, Response response, @Nullable Exception e) { + System.out.println("onAfter"); + } + + @Override + public void upProgress(long currentSize, long totalSize, float progress) { + System.out.println("upProgress -- " + totalSize + " " + currentSize + " " + progress); + } + + @Override + public void downloadProgress(long currentSize, long totalSize, float progress) { + System.out.println("downloadProgress -- " + totalSize + " " + currentSize + " " + progress); + } + + @Override + public void onError(Request request, @Nullable Response response, @Nullable Exception e) { + System.out.println("onError"); + super.onError(request, response, e); + } +} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 00000000..a96e493b --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..cde69bcc Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..c133a0cb Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..bfa42f0e Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..324e72cd Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..aee44e13 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/values-w820dp/dimens.xml b/app/src/main/res/values-w820dp/dimens.xml new file mode 100644 index 00000000..63fc8164 --- /dev/null +++ b/app/src/main/res/values-w820dp/dimens.xml @@ -0,0 +1,6 @@ + + + 64dp + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 00000000..3ab3e9cb --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #3F51B5 + #303F9F + #FF4081 + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml new file mode 100644 index 00000000..47c82246 --- /dev/null +++ b/app/src/main/res/values/dimens.xml @@ -0,0 +1,5 @@ + + + 16dp + 16dp + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 00000000..7b1e38fc --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + OkHttpDemo + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..5885930d --- /dev/null +++ b/app/src/main/res/values/styles.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/build.gradle b/build.gradle new file mode 100644 index 00000000..e0b366a7 --- /dev/null +++ b/build.gradle @@ -0,0 +1,23 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.5.0' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 00000000..1d3591c8 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,18 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..05ef575b Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..f23df6e4 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Wed Oct 21 11:34:03 PDT 2015 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip diff --git a/gradlew b/gradlew new file mode 100644 index 00000000..9d82f789 --- /dev/null +++ b/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 00000000..8a0b282a --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/library_okhttputils/.gitignore b/library_okhttputils/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/library_okhttputils/.gitignore @@ -0,0 +1 @@ +/build diff --git a/library_okhttputils/build.gradle b/library_okhttputils/build.gradle new file mode 100644 index 00000000..f0a3bcda --- /dev/null +++ b/library_okhttputils/build.gradle @@ -0,0 +1,26 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 23 + buildToolsVersion "23.0.2" + + defaultConfig { + minSdkVersion 16 + targetSdkVersion 23 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:support-annotations:23.1.1' + compile 'com.squareup.okhttp3:okhttp:3.0.0-RC1' + compile 'com.google.code.gson:gson:2.5' +} diff --git a/library_okhttputils/proguard-rules.pro b/library_okhttputils/proguard-rules.pro new file mode 100644 index 00000000..f727142b --- /dev/null +++ b/library_okhttputils/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in E:\Android\SDK/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/library_okhttputils/src/main/AndroidManifest.xml b/library_okhttputils/src/main/AndroidManifest.xml new file mode 100644 index 00000000..c4ec427d --- /dev/null +++ b/library_okhttputils/src/main/AndroidManifest.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/library_okhttputils/src/main/java/com/lzy/okhttputils/ImageUtils.java b/library_okhttputils/src/main/java/com/lzy/okhttputils/ImageUtils.java new file mode 100644 index 00000000..028580ac --- /dev/null +++ b/library_okhttputils/src/main/java/com/lzy/okhttputils/ImageUtils.java @@ -0,0 +1,126 @@ +package com.lzy.okhttputils; + +import android.graphics.BitmapFactory; +import android.util.DisplayMetrics; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import java.io.InputStream; +import java.lang.reflect.Field; + +/** 图片的相关工具类 */ +public class ImageUtils { + + /** 根据InputStream获取图片实际的宽度和高度 */ + public static ImageSize getImageSize(InputStream imageStream) { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeStream(imageStream, null, options); + return new ImageSize(options.outWidth, options.outHeight); + } + + public static int calculateInSampleSize(ImageSize srcSize, ImageSize targetSize) { + // 源图片的宽度 + int width = srcSize.width; + int height = srcSize.height; + int inSampleSize = 1; + + int reqWidth = targetSize.width; + int reqHeight = targetSize.height; + + if (width > reqWidth && height > reqHeight) { + // 计算出实际宽度和目标宽度的比率 + int widthRatio = Math.round((float) width / (float) reqWidth); + int heightRatio = Math.round((float) height / (float) reqHeight); + inSampleSize = Math.max(widthRatio, heightRatio); + } + return inSampleSize; + } + + /** 根据ImageView获适当的压缩的宽和高 */ + public static ImageSize getImageViewSize(View view) { + ImageSize imageSize = new ImageSize(); + imageSize.width = getExpectWidth(view); + imageSize.height = getExpectHeight(view); + return imageSize; + } + + /** 根据view获得期望的高度 */ + private static int getExpectHeight(View view) { + int height = 0; + if (view == null) return 0; + + final ViewGroup.LayoutParams params = view.getLayoutParams(); + //如果是WRAP_CONTENT,此时图片还没加载,getWidth根本无效 + if (params != null && params.height != ViewGroup.LayoutParams.WRAP_CONTENT) { + height = view.getHeight(); // 获得实际的高度 + } + // 获得布局文件中的声明的高度 + if (height <= 0 && params != null) height = params.height; + // 获得设置的最大的高度 + if (height <= 0) height = getImageViewFieldValue(view, "mMaxHeight"); + //如果宽度还是没有获取到,憋大招,使用屏幕的高度 + if (height <= 0) { + DisplayMetrics displayMetrics = view.getContext().getResources().getDisplayMetrics(); + height = displayMetrics.heightPixels; + } + return height; + } + + /** 根据view获得期望的宽度 */ + private static int getExpectWidth(View view) { + int width = 0; + if (view == null) return 0; + + final ViewGroup.LayoutParams params = view.getLayoutParams(); + //如果是WRAP_CONTENT,此时图片还没加载,getWidth根本无效 + if (params != null && params.width != ViewGroup.LayoutParams.WRAP_CONTENT) { + width = view.getWidth(); // 获得实际的宽度 + } + // 获得布局文件中的声明的宽度 + if (width <= 0 && params != null) width = params.width; + // 获得设置的最大的宽度 + if (width <= 0) width = getImageViewFieldValue(view, "mMaxWidth"); + //如果宽度还是没有获取到,憋大招,使用屏幕的宽度 + if (width <= 0) { + DisplayMetrics displayMetrics = view.getContext().getResources().getDisplayMetrics(); + width = displayMetrics.widthPixels; + } + return width; + } + + /** 通过反射获取ImageView的某个属性值 */ + private static int getImageViewFieldValue(Object object, String fieldName) { + int value = 0; + try { + Field field = ImageView.class.getDeclaredField(fieldName); + field.setAccessible(true); + int fieldValue = field.getInt(object); + if (fieldValue > 0 && fieldValue < Integer.MAX_VALUE) { + value = fieldValue; + } + } catch (Exception e) { + e.printStackTrace(); + } + return value; + } + + public static class ImageSize { + int width; + int height; + + public ImageSize() { + } + + public ImageSize(int width, int height) { + this.width = width; + this.height = height; + } + + @Override + public String toString() { + return "ImageSize{" + "width=" + width + ", height=" + height + '}'; + } + } +} diff --git a/library_okhttputils/src/main/java/com/lzy/okhttputils/L.java b/library_okhttputils/src/main/java/com/lzy/okhttputils/L.java new file mode 100644 index 00000000..2a58e398 --- /dev/null +++ b/library_okhttputils/src/main/java/com/lzy/okhttputils/L.java @@ -0,0 +1,30 @@ +package com.lzy.okhttputils; + +import android.util.Log; + +/** 日志工具类 */ +public class L { + public static boolean debug = false; + public static String tag = "OkHttpUtils"; + + public static void v(String msg) { + if (debug) Log.v(tag, msg); + } + + public static void d(String msg) { + if (debug) Log.d(tag, msg); + } + + public static void i(String msg) { + if (debug) Log.i(tag, msg); + } + + public static void w(String msg) { + if (debug) Log.w(tag, msg); + } + + public static void e(String msg) { + if (debug) Log.e(tag, msg); + } +} + diff --git a/library_okhttputils/src/main/java/com/lzy/okhttputils/OkHttpUtils.java b/library_okhttputils/src/main/java/com/lzy/okhttputils/OkHttpUtils.java new file mode 100644 index 00000000..bae0e50d --- /dev/null +++ b/library_okhttputils/src/main/java/com/lzy/okhttputils/OkHttpUtils.java @@ -0,0 +1,132 @@ +package com.lzy.okhttputils; + +import android.os.Handler; +import android.os.Looper; +import android.text.TextUtils; + +import com.lzy.okhttputils.cookie.SimpleCookieJar; +import com.lzy.okhttputils.https.HttpsUtils; +import com.lzy.okhttputils.request.GetRequest; +import com.lzy.okhttputils.request.PostRequest; + +import java.io.InputStream; +import java.util.concurrent.TimeUnit; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLSession; + +import okhttp3.Call; +import okhttp3.OkHttpClient; + +/** + * ================================================ + * 作 者:廖子尧 + * 版 本:1.0 + * 创建日期:2016/1/12 + * 描 述:网络请求的入口类 + * 修订历史: + * 本框架基于 张鸿洋 https://github.com/hongyangAndroid/okhttp-utils + * 和 https://github.com/pengjianbo/OkHttpFinal 两个框架修改而成, + * 目前Get,Post的请求已经完成,支持大文件上传下载,上传进度回调,下载进度回调, + * 表单上传(多文件和多参数一起上传),链式调用,整合Gson,自动解析返回对象, + * 支持Https和自签名证书,支持cookie自动管理, + * 。。。。。。。。。。 + * 后期将要实现的功能,统一的上传管理和下载管理 + * ================================================ + */ +public class OkHttpUtils { + public static final int DEFAULT_MILLISECONDS = 5000; //默认的超时时间 + private static OkHttpUtils mInstance; //单例 + private Handler mDelivery; //用于在主线程执行的调度器 + private OkHttpClient.Builder okHttpClientBuilder; //ok请求的客户端 + + private OkHttpUtils() { + okHttpClientBuilder = new OkHttpClient.Builder(); + //允许cookie的自动化管理 + okHttpClientBuilder.cookieJar(new SimpleCookieJar()); + mDelivery = new Handler(Looper.getMainLooper()); + // 此类是用于主机名验证的基接口。 在握手期间,如果 URL 的主机名和服务器的标识主机名不匹配, + // 则验证机制可以回调此接口的实现程序来确定是否应该允许此连接。策略可以是基于证书的或依赖于其他验证方案。 + // 当验证 URL 主机名使用的默认规则失败时使用这些回调。如果主机名是可接受的,则返回 true + okHttpClientBuilder.hostnameVerifier(new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }); + } + + public static OkHttpUtils getInstance() { + if (mInstance == null) { + synchronized (OkHttpUtils.class) { + if (mInstance == null) { + mInstance = new OkHttpUtils(); + } + } + } + return mInstance; + } + + public Handler getDelivery() { + return mDelivery; + } + + public OkHttpClient getOkHttpClient() { + return okHttpClientBuilder.build(); + } + + /** get请求 */ + public static GetRequest get(String url) { + return new GetRequest(url); + } + + /** post请求 */ + public static PostRequest post(String url) { + return new PostRequest(url); + } + + /** 调试模式 */ + public static void debug(boolean debug, String tag) { + L.debug = debug; + L.tag = tag; + } + + /** https的全局自签名证书 */ + public OkHttpUtils setCertificates(InputStream... certificates) { + okHttpClientBuilder.sslSocketFactory(HttpsUtils.getSslSocketFactory(certificates, null, null)); + return this; + } + + /** 全局读取超时时间 */ + public OkHttpUtils setReadTimeOut(int readTimeOut) { + okHttpClientBuilder.readTimeout(readTimeOut, TimeUnit.MILLISECONDS); + return this; + } + + /** 全局写入超时时间 */ + public OkHttpUtils setWriteTimeOut(int writeTimeout) { + okHttpClientBuilder.writeTimeout(writeTimeout, TimeUnit.MILLISECONDS); + return this; + } + + /** 全局连接超时时间 */ + public OkHttpUtils setConnectTimeout(int connectTimeout) { + okHttpClientBuilder.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS); + return this; + } + + /** 根据Tag取消请求 */ + public void cancelTag(Object tag) { + for (Call call : getOkHttpClient().dispatcher().queuedCalls()) { + if (tag.equals(call.request().tag())) { + call.cancel(); + } + } + for (Call call : getOkHttpClient().dispatcher().runningCalls()) { + if (tag.equals(call.request().tag())) { + call.cancel(); + } + } + } +} + diff --git a/library_okhttputils/src/main/java/com/lzy/okhttputils/callback/AbsCallback.java b/library_okhttputils/src/main/java/com/lzy/okhttputils/callback/AbsCallback.java new file mode 100644 index 00000000..4e3934b2 --- /dev/null +++ b/library_okhttputils/src/main/java/com/lzy/okhttputils/callback/AbsCallback.java @@ -0,0 +1,60 @@ +package com.lzy.okhttputils.callback; + +import android.support.annotation.Nullable; + +import com.lzy.okhttputils.L; +import com.lzy.okhttputils.request.BaseRequest; + +import okhttp3.Request; +import okhttp3.Response; + +/** + * ================================================ + * 作 者:廖子尧 + * 版 本:1.0 + * 创建日期:2016/1/14 + * 描 述:抽象的回调接口 + * 修订历史: + * ================================================ + */ +public abstract class AbsCallback { + /** 请求网络开始前,UI线程 */ + public void onBefore(BaseRequest request) { + } + + /** 请求网络结束后,UI线程 */ + public void onAfter(@Nullable T t, Request request, Response response, @Nullable Exception e) { + } + + /** Post执行上传过程中的进度回调,get请求不回调,UI线程 */ + public void upProgress(long currentSize, long totalSize, float progress) { + } + + /** 执行下载过程中的进度回调,UI线程 */ + public void downloadProgress(long currentSize, long totalSize, float progress) { + } + + /** 拿到响应后,将数据转换成需要的格式,子线程中执行,可以是耗时操作 */ + public abstract T parseNetworkResponse(Response response) throws Exception; + + /** 对返回数据进行操作的回调, UI线程 */ + public abstract void onResponse(T t); + + /** 请求失败,响应错误,数据解析错误等,都会回调该方法, UI线程 */ + public void onError(Request request, @Nullable Response response, @Nullable Exception e) { + if (e != null) e.printStackTrace(); + else if (response != null) L.e("服务器内部错误,或者找不到页面等"); + } + + public static final AbsCallback CALLBACK_DEFAULT = new AbsCallback() { + + @Override + public Response parseNetworkResponse(Response response) throws Exception { + return response; + } + + @Override + public void onResponse(Object response) { + } + }; +} \ No newline at end of file diff --git a/library_okhttputils/src/main/java/com/lzy/okhttputils/callback/BeanCallBack.java b/library_okhttputils/src/main/java/com/lzy/okhttputils/callback/BeanCallBack.java new file mode 100644 index 00000000..4aa4b486 --- /dev/null +++ b/library_okhttputils/src/main/java/com/lzy/okhttputils/callback/BeanCallBack.java @@ -0,0 +1,41 @@ +package com.lzy.okhttputils.callback; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +import okhttp3.Response; + +/** + * ================================================ + * 作 者:廖子尧 + * 版 本:1.0 + * 创建日期:2016/1/14 + * 描 述:默认将返回的数据解析成需要的Bean,可以是 Bean,String,List,Map + * 修订历史: + * ================================================ + */ +public abstract class BeanCallBack extends AbsCallback { + + @Override + public T parseNetworkResponse(Response response) throws Exception { + Type type = this.getClass().getGenericSuperclass(); + if (type instanceof ParameterizedType) { + //如果用户写了泛型,就会进入这里,否者不会执行 + ParameterizedType parameterizedType = (ParameterizedType) type; + Type beanType = parameterizedType.getActualTypeArguments()[0]; + if (beanType == String.class) { + //如果是String类型,直接返回字符串 + return (T) response.body().string(); + } else { + //如果是 Bean List Map ,则解析完后返回 + return new Gson().fromJson(response.body().string(), beanType); + } + } else { + //如果没有写泛型,直接返回Response对象 + return (T) response; + } + } +} diff --git a/library_okhttputils/src/main/java/com/lzy/okhttputils/callback/BitmapCallback.java b/library_okhttputils/src/main/java/com/lzy/okhttputils/callback/BitmapCallback.java new file mode 100644 index 00000000..a3c5e4eb --- /dev/null +++ b/library_okhttputils/src/main/java/com/lzy/okhttputils/callback/BitmapCallback.java @@ -0,0 +1,23 @@ +package com.lzy.okhttputils.callback; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; + +import okhttp3.Response; + +/** + * ================================================ + * 作 者:廖子尧 + * 版 本:1.0 + * 创建日期:2016/1/12 + * 描 述:返回图片的Bitmap,这里没有进行图片的缩放,可能会发生 OOM + * 修订历史: + * ================================================ + */ +public abstract class BitmapCallback extends AbsCallback { + + @Override + public Bitmap parseNetworkResponse(Response response) throws Exception { + return BitmapFactory.decodeStream(response.body().byteStream()); + } +} diff --git a/library_okhttputils/src/main/java/com/lzy/okhttputils/callback/FileCallBack.java b/library_okhttputils/src/main/java/com/lzy/okhttputils/callback/FileCallBack.java new file mode 100644 index 00000000..a325041f --- /dev/null +++ b/library_okhttputils/src/main/java/com/lzy/okhttputils/callback/FileCallBack.java @@ -0,0 +1,82 @@ +package com.lzy.okhttputils.callback; + +import com.lzy.okhttputils.OkHttpUtils; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import okhttp3.Response; + +/** + * ================================================ + * 作 者:廖子尧 + * 版 本:1.0 + * 创建日期:2016/1/12 + * 描 述:文件的回调下载进度监听 + * 修订历史: + * ================================================ + */ +public abstract class FileCallBack extends AbsCallback { + /** 目标文件存储的文件夹路径 */ + private String destFileDir; + /** 目标文件存储的文件名 */ + private String destFileName; + + /** + * @param destFileDir 要保存的目标文件夹 + * @param destFileName 要保存的文件名 + */ + public FileCallBack(String destFileDir, String destFileName) { + this.destFileDir = destFileDir; + this.destFileName = destFileName; + } + + @Override + public File parseNetworkResponse(Response response) throws Exception { + return saveFile(response); + } + + private File saveFile(Response response) throws IOException { + File dir = new File(destFileDir); + if (!dir.exists()) dir.mkdirs(); + File file = new File(dir, destFileName); + if (file.exists()) file.delete(); + + InputStream is = null; + byte[] buf = new byte[2048]; + FileOutputStream fos = null; + try { + is = response.body().byteStream(); + final long total = response.body().contentLength(); + long sum = 0; + int len = 0; + fos = new FileOutputStream(file); + while ((len = is.read(buf)) != -1) { + sum += len; + fos.write(buf, 0, len); + final long finalSum = sum; + OkHttpUtils.getInstance().getDelivery().post(new Runnable() { + @Override + public void run() { + downloadProgress(finalSum, total, finalSum * 1.0f / total); //进度回调的方法 + } + }); + } + fos.flush(); + return file; + } finally { + try { + if (is != null) is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + try { + if (fos != null) fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } +} diff --git a/library_okhttputils/src/main/java/com/lzy/okhttputils/callback/StringCallback.java b/library_okhttputils/src/main/java/com/lzy/okhttputils/callback/StringCallback.java new file mode 100644 index 00000000..96881676 --- /dev/null +++ b/library_okhttputils/src/main/java/com/lzy/okhttputils/callback/StringCallback.java @@ -0,0 +1,24 @@ +package com.lzy.okhttputils.callback; + +import java.io.IOException; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +import okhttp3.Response; + +/** + * ================================================ + * 作 者:廖子尧 + * 版 本:1.0 + * 创建日期:2016/1/12 + * 描 述:返回字符串类型的数据,可以使用 BeanCallBack 代替 + * 修订历史: + * ================================================ + */ +public abstract class StringCallback extends AbsCallback { + + @Override + public String parseNetworkResponse(Response response) throws IOException { + return response.body().string(); + } +} diff --git a/library_okhttputils/src/main/java/com/lzy/okhttputils/cookie/PersistentCookieStore.java b/library_okhttputils/src/main/java/com/lzy/okhttputils/cookie/PersistentCookieStore.java new file mode 100644 index 00000000..6e362066 --- /dev/null +++ b/library_okhttputils/src/main/java/com/lzy/okhttputils/cookie/PersistentCookieStore.java @@ -0,0 +1,235 @@ +package com.lzy.okhttputils.cookie; + +import android.content.Context; +import android.content.SharedPreferences; +import android.text.TextUtils; +import android.util.Log; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.net.CookieStore; +import java.net.HttpCookie; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + *
+ *     OkHttpClient client = new OkHttpClient.Builder()
+ *             .cookieJar(new JavaNetCookieJar(new CookieManager(
+ *                     new PersistentCookieStore(getApplicationContext()),
+ *                             CookiePolicy.ACCEPT_ALL))
+ *             .build();
+ * 
+ * from http://stackoverflow.com/questions/25461792/persistent-cookie-store-using-okhttp-2-on-android + *
+ * A persistent cookie store which implements the Apache HttpClient CookieStore interface. + * Cookies are stored and will persist on the user's device between application sessions since they + * are serialized and stored in SharedPreferences. Instances of this class are + * designed to be used with AsyncHttpClient#setCookieStore, but can also be used with a + * regular old apache HttpClient/HttpContext if you prefer. + */ +public class PersistentCookieStore implements CookieStore { + + private static final String LOG_TAG = "PersistentCookieStore"; + private static final String COOKIE_PREFS = "CookiePrefsFile"; + private static final String COOKIE_NAME_PREFIX = "cookie_"; + + private final HashMap> cookies; + private final SharedPreferences cookiePrefs; + + /** + * Construct a persistent cookie store. + * + * @param context Context to attach cookie store to + */ + public PersistentCookieStore(Context context) { + cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, 0); + cookies = new HashMap>(); + + // Load any previously stored cookies into the store + Map prefsMap = cookiePrefs.getAll(); + for (Map.Entry entry : prefsMap.entrySet()) { + if (((String) entry.getValue()) != null && !((String) entry.getValue()).startsWith(COOKIE_NAME_PREFIX)) { + String[] cookieNames = TextUtils.split((String) entry.getValue(), ","); + for (String name : cookieNames) { + String encodedCookie = cookiePrefs.getString(COOKIE_NAME_PREFIX + name, null); + if (encodedCookie != null) { + HttpCookie decodedCookie = decodeCookie(encodedCookie); + if (decodedCookie != null) { + if (!cookies.containsKey(entry.getKey())) + cookies.put(entry.getKey(), new ConcurrentHashMap()); + cookies.get(entry.getKey()).put(name, decodedCookie); + } + } + } + } + } + } + + @Override + public void add(URI uri, HttpCookie cookie) { + String name = getCookieToken(uri, cookie); + + // Save cookie into local store, or remove if expired + if (!cookie.hasExpired()) { + if (!cookies.containsKey(uri.getHost())) + cookies.put(uri.getHost(), new ConcurrentHashMap()); + cookies.get(uri.getHost()).put(name, cookie); + } else { + if (cookies.containsKey(uri.toString())) cookies.get(uri.getHost()).remove(name); + } + + // Save cookie into persistent store + SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); + prefsWriter.putString(uri.getHost(), TextUtils.join(",", cookies.get(uri.getHost()).keySet())); + prefsWriter.putString(COOKIE_NAME_PREFIX + name, encodeCookie(new SerializableHttpCookie(cookie))); + prefsWriter.commit(); + } + + protected String getCookieToken(URI uri, HttpCookie cookie) { + return cookie.getName() + cookie.getDomain(); + } + + @Override + public List get(URI uri) { + ArrayList ret = new ArrayList(); + if (cookies.containsKey(uri.getHost())) ret.addAll(cookies.get(uri.getHost()).values()); + return ret; + } + + @Override + public boolean removeAll() { + SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); + prefsWriter.clear(); + prefsWriter.commit(); + cookies.clear(); + return true; + } + + @Override + public boolean remove(URI uri, HttpCookie cookie) { + String name = getCookieToken(uri, cookie); + + if (cookies.containsKey(uri.getHost()) && cookies.get(uri.getHost()).containsKey(name)) { + cookies.get(uri.getHost()).remove(name); + + SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); + if (cookiePrefs.contains(COOKIE_NAME_PREFIX + name)) { + prefsWriter.remove(COOKIE_NAME_PREFIX + name); + } + prefsWriter.putString(uri.getHost(), TextUtils.join(",", cookies.get(uri.getHost()).keySet())); + prefsWriter.commit(); + + return true; + } else { + return false; + } + } + + @Override + public List getCookies() { + ArrayList ret = new ArrayList(); + for (String key : cookies.keySet()) + ret.addAll(cookies.get(key).values()); + + return ret; + } + + @Override + public List getURIs() { + ArrayList ret = new ArrayList(); + for (String key : cookies.keySet()) + try { + ret.add(new URI(key)); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + + return ret; + } + + /** + * Serializes Cookie object into String + * + * @param cookie cookie to be encoded, can be null + * @return cookie encoded as String + */ + protected String encodeCookie(SerializableHttpCookie cookie) { + if (cookie == null) return null; + ByteArrayOutputStream os = new ByteArrayOutputStream(); + try { + ObjectOutputStream outputStream = new ObjectOutputStream(os); + outputStream.writeObject(cookie); + } catch (IOException e) { + Log.d(LOG_TAG, "IOException in encodeCookie", e); + return null; + } + + return byteArrayToHexString(os.toByteArray()); + } + + /** + * Returns cookie decoded from cookie string + * + * @param cookieString string of cookie as returned from http request + * @return decoded cookie or null if exception occured + */ + protected HttpCookie decodeCookie(String cookieString) { + byte[] bytes = hexStringToByteArray(cookieString); + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); + HttpCookie cookie = null; + try { + ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); + cookie = ((SerializableHttpCookie) objectInputStream.readObject()).getCookie(); + } catch (IOException e) { + Log.d(LOG_TAG, "IOException in decodeCookie", e); + } catch (ClassNotFoundException e) { + Log.d(LOG_TAG, "ClassNotFoundException in decodeCookie", e); + } + + return cookie; + } + + /** + * Using some super basic byte array <-> hex conversions so we don't have to rely on any + * large Base64 libraries. Can be overridden if you like! + * + * @param bytes byte array to be converted + * @return string containing hex values + */ + protected String byteArrayToHexString(byte[] bytes) { + StringBuilder sb = new StringBuilder(bytes.length * 2); + for (byte element : bytes) { + int v = element & 0xff; + if (v < 16) { + sb.append('0'); + } + sb.append(Integer.toHexString(v)); + } + return sb.toString().toUpperCase(Locale.US); + } + + /** + * Converts hex values from strings to byte arra + * + * @param hexString string of hex-encoded values + * @return decoded byte array + */ + protected byte[] hexStringToByteArray(String hexString) { + int len = hexString.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i + 1), 16)); + } + return data; + } +} \ No newline at end of file diff --git a/library_okhttputils/src/main/java/com/lzy/okhttputils/cookie/SerializableHttpCookie.java b/library_okhttputils/src/main/java/com/lzy/okhttputils/cookie/SerializableHttpCookie.java new file mode 100644 index 00000000..a6a82e25 --- /dev/null +++ b/library_okhttputils/src/main/java/com/lzy/okhttputils/cookie/SerializableHttpCookie.java @@ -0,0 +1,56 @@ +package com.lzy.okhttputils.cookie; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.net.HttpCookie; + +/** from http://stackoverflow.com/questions/25461792/persistent-cookie-store-using-okhttp-2-on-android */ +public class SerializableHttpCookie implements Serializable { + private static final long serialVersionUID = 6374381323722046732L; + + private transient final HttpCookie cookie; + private transient HttpCookie clientCookie; + + public SerializableHttpCookie(HttpCookie cookie) { + this.cookie = cookie; + } + + public HttpCookie getCookie() { + HttpCookie bestCookie = cookie; + if (clientCookie != null) { + bestCookie = clientCookie; + } + return bestCookie; + } + + private void writeObject(ObjectOutputStream out) throws IOException { + out.writeObject(cookie.getName()); + out.writeObject(cookie.getValue()); + out.writeObject(cookie.getComment()); + out.writeObject(cookie.getCommentURL()); + out.writeObject(cookie.getDomain()); + out.writeLong(cookie.getMaxAge()); + out.writeObject(cookie.getPath()); + out.writeObject(cookie.getPortlist()); + out.writeInt(cookie.getVersion()); + out.writeBoolean(cookie.getSecure()); + out.writeBoolean(cookie.getDiscard()); + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + String name = (String) in.readObject(); + String value = (String) in.readObject(); + clientCookie = new HttpCookie(name, value); + clientCookie.setComment((String) in.readObject()); + clientCookie.setCommentURL((String) in.readObject()); + clientCookie.setDomain((String) in.readObject()); + clientCookie.setMaxAge(in.readLong()); + clientCookie.setPath((String) in.readObject()); + clientCookie.setPortlist((String) in.readObject()); + clientCookie.setVersion(in.readInt()); + clientCookie.setSecure(in.readBoolean()); + clientCookie.setDiscard(in.readBoolean()); + } +} \ No newline at end of file diff --git a/library_okhttputils/src/main/java/com/lzy/okhttputils/cookie/SimpleCookieJar.java b/library_okhttputils/src/main/java/com/lzy/okhttputils/cookie/SimpleCookieJar.java new file mode 100644 index 00000000..1381d60c --- /dev/null +++ b/library_okhttputils/src/main/java/com/lzy/okhttputils/cookie/SimpleCookieJar.java @@ -0,0 +1,30 @@ +package com.lzy.okhttputils.cookie; + +import java.util.ArrayList; +import java.util.List; + +import okhttp3.Cookie; +import okhttp3.CookieJar; +import okhttp3.HttpUrl; + +/** cookie的自动化管理 */ +public final class SimpleCookieJar implements CookieJar { + + private final List allCookies = new ArrayList<>(); + + @Override + public synchronized void saveFromResponse(HttpUrl url, List cookies) { + allCookies.addAll(cookies); + } + + @Override + public synchronized List loadForRequest(HttpUrl url) { + List result = new ArrayList<>(); + for (Cookie cookie : allCookies) { + if (cookie.matches(url)) { + result.add(cookie); + } + } + return result; + } +} diff --git a/library_okhttputils/src/main/java/com/lzy/okhttputils/https/HttpsUtils.java b/library_okhttputils/src/main/java/com/lzy/okhttputils/https/HttpsUtils.java new file mode 100644 index 00000000..07069e3b --- /dev/null +++ b/library_okhttputils/src/main/java/com/lzy/okhttputils/https/HttpsUtils.java @@ -0,0 +1,136 @@ +package com.lzy.okhttputils.https; + +import java.io.IOException; +import java.io.InputStream; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +/** Https相关的工具类 */ +public class HttpsUtils { + public static SSLSocketFactory getSslSocketFactory(InputStream[] certificates, InputStream bksFile, String password) { + try { + TrustManager[] trustManagers = prepareTrustManager(certificates); + KeyManager[] keyManagers = prepareKeyManager(bksFile, password); + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(keyManagers, new TrustManager[]{new MyTrustManager(chooseTrustManager(trustManagers))}, new SecureRandom()); + return sslContext.getSocketFactory(); + } catch (NoSuchAlgorithmException e) { + throw new AssertionError(e); + } catch (KeyManagementException e) { + throw new AssertionError(e); + } catch (KeyStoreException e) { + throw new AssertionError(e); + } + } + + private static TrustManager[] prepareTrustManager(InputStream... certificates) { + if (certificates == null || certificates.length <= 0) return null; + try { + CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(null); + int index = 0; + for (InputStream certificate : certificates) { + String certificateAlias = Integer.toString(index++); + keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate)); + try { + if (certificate != null) certificate.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + TrustManagerFactory trustManagerFactory; + trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(keyStore); + return trustManagerFactory.getTrustManagers(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (CertificateException e) { + e.printStackTrace(); + } catch (KeyStoreException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + private static KeyManager[] prepareKeyManager(InputStream bksFile, String password) { + try { + if (bksFile == null || password == null) return null; + KeyStore clientKeyStore = KeyStore.getInstance("BKS"); + clientKeyStore.load(bksFile, password.toCharArray()); + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(clientKeyStore, password.toCharArray()); + return keyManagerFactory.getKeyManagers(); + } catch (KeyStoreException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (UnrecoverableKeyException e) { + e.printStackTrace(); + } catch (CertificateException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + private static X509TrustManager chooseTrustManager(TrustManager[] trustManagers) { + for (TrustManager trustManager : trustManagers) { + if (trustManager instanceof X509TrustManager) { + return (X509TrustManager) trustManager; + } + } + return null; + } + + private static class MyTrustManager implements X509TrustManager { + private X509TrustManager defaultTrustManager; + private X509TrustManager localTrustManager; + + public MyTrustManager(X509TrustManager localTrustManager) throws NoSuchAlgorithmException, KeyStoreException { + TrustManagerFactory var4 = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + var4.init((KeyStore) null); + defaultTrustManager = chooseTrustManager(var4.getTrustManagers()); + this.localTrustManager = localTrustManager; + } + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + try { + defaultTrustManager.checkServerTrusted(chain, authType); + } catch (CertificateException ce) { + localTrustManager.checkServerTrusted(chain, authType); + } + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + } +} diff --git a/library_okhttputils/src/main/java/com/lzy/okhttputils/model/RequestHeaders.java b/library_okhttputils/src/main/java/com/lzy/okhttputils/model/RequestHeaders.java new file mode 100644 index 00000000..0b906493 --- /dev/null +++ b/library_okhttputils/src/main/java/com/lzy/okhttputils/model/RequestHeaders.java @@ -0,0 +1,43 @@ +package com.lzy.okhttputils.model; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * ================================================ + * 作 者:廖子尧 + * 版 本:1.0 + * 创建日期:2015/10/10 + * 描 述:请求头的包装类 + * 修订历史: + * ================================================ + */ +public class RequestHeaders { + + public ConcurrentHashMap headersMap; + + private void init() { + headersMap = new ConcurrentHashMap<>(); + } + + public RequestHeaders() { + init(); + } + + public RequestHeaders(String key, String value) { + init(); + put(key, value); + } + + public void put(String key, String value) { + if (key != null && value != null) { + headersMap.put(key, value); + } + } + + public void put(RequestHeaders headers) { + if (headers != null) { + if (headers.headersMap != null && !headers.headersMap.isEmpty()) + headersMap.putAll(headers.headersMap); + } + } +} diff --git a/library_okhttputils/src/main/java/com/lzy/okhttputils/model/RequestParams.java b/library_okhttputils/src/main/java/com/lzy/okhttputils/model/RequestParams.java new file mode 100644 index 00000000..c980d8f3 --- /dev/null +++ b/library_okhttputils/src/main/java/com/lzy/okhttputils/model/RequestParams.java @@ -0,0 +1,104 @@ +package com.lzy.okhttputils.model; + +import java.io.File; +import java.net.FileNameMap; +import java.net.URLConnection; +import java.util.concurrent.ConcurrentHashMap; + +/** + * ================================================ + * 作 者:廖子尧 + * 版 本:1.0 + * 创建日期:2015/10/9 + * 描 述:请求参数的包装类 + * 修订历史: + * ================================================ + */ +public class RequestParams { + + /** 普通的键值对参数 */ + public ConcurrentHashMap urlParamsMap; + + /** 文件的键值对参数 */ + public ConcurrentHashMap fileParamsMap; + + private void init() { + urlParamsMap = new ConcurrentHashMap<>(); + fileParamsMap = new ConcurrentHashMap<>(); + } + + public RequestParams() { + init(); + } + + public RequestParams(String key, String value) { + init(); + put(key, value); + } + + public RequestParams(String key, File file) { + init(); + put(key, file); + } + + public void put(RequestParams params) { + if (params != null) { + if (params.urlParamsMap != null && !params.urlParamsMap.isEmpty()) + urlParamsMap.putAll(params.urlParamsMap); + if (params.fileParamsMap != null && !params.fileParamsMap.isEmpty()) + fileParamsMap.putAll(params.fileParamsMap); + } + } + + public void put(String key, String value) { + if (key != null && value != null) { + urlParamsMap.put(key, value); + } + } + + public void put(String key, File file) { + put(key, file, file.getName()); + } + + public void put(String key, File file, String fileName) { + put(key, file, fileName, guessMimeType(fileName)); + } + + public void put(String key, File file, String fileName, String contentType) { + if (key != null) { + fileParamsMap.put(key, new FileWrapper(file, fileName, contentType)); + } + } + + private String guessMimeType(String path) { + FileNameMap fileNameMap = URLConnection.getFileNameMap(); + String contentType = fileNameMap.getContentTypeFor(path); + if (contentType == null) { + contentType = "application/octet-stream"; + } + return contentType; + } + + /** + * 文件类型的包装类 + */ + public static class FileWrapper { + public File file; + public String fileName; + public String contentType; + + public FileWrapper(File file, String fileName, String contentType) { + this.file = file; + this.fileName = fileName; + this.contentType = contentType; + } + + public String getFileName() { + if (fileName != null) { + return fileName; + } else { + return "nofilename"; + } + } + } +} \ No newline at end of file diff --git a/library_okhttputils/src/main/java/com/lzy/okhttputils/request/BaseRequest.java b/library_okhttputils/src/main/java/com/lzy/okhttputils/request/BaseRequest.java new file mode 100644 index 00000000..b75cdc68 --- /dev/null +++ b/library_okhttputils/src/main/java/com/lzy/okhttputils/request/BaseRequest.java @@ -0,0 +1,232 @@ +package com.lzy.okhttputils.request; + +import android.support.annotation.NonNull; + +import com.lzy.okhttputils.OkHttpUtils; +import com.lzy.okhttputils.callback.AbsCallback; +import com.lzy.okhttputils.https.HttpsUtils; +import com.lzy.okhttputils.model.RequestHeaders; +import com.lzy.okhttputils.model.RequestParams; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +import okhttp3.Call; +import okhttp3.Headers; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +/** + * ================================================ + * 作 者:廖子尧 + * 版 本:1.0 + * 创建日期:2016/1/12 + * 描 述:所有请求的基类,其中泛型 R 主要用于属性设置方法后,返回对应的子类型,以便于实现链式调用 + * 修订历史: + * ================================================ + */ +public abstract class BaseRequest { + protected String url; + protected Object tag; + protected long readTimeOut; + protected long writeTimeOut; + protected long connectTimeout; + protected InputStream[] certificates; + protected RequestParams params = new RequestParams(); + protected RequestHeaders headers = new RequestHeaders(); + + public BaseRequest(String url){ + this.url = url; + } + + public R url(@NonNull String url) { + this.url = url; + return (R) this; + } + + public R tag(Object tag) { + this.tag = tag; + return (R) this; + } + + public R readTimeOut(long readTimeOut) { + this.readTimeOut = readTimeOut; + return (R) this; + } + + public R writeTimeOut(long writeTimeOut) { + this.writeTimeOut = writeTimeOut; + return (R) this; + } + + public R connTimeOut(long connTimeOut) { + this.connectTimeout = connTimeOut; + return (R) this; + } + + public R setCertificates(@NonNull InputStream... certificates) { + this.certificates = certificates; + return (R) this; + } + + public R headers(RequestHeaders headers) { + this.headers.put(headers); + return (R) this; + } + + public R headers(String key, String value) { + headers.put(key, value); + return (R) this; + } + + public R params(RequestParams params) { + this.params.put(params); + return (R) this; + } + + public R params(String key, String value) { + params.put(key, value); + return (R) this; + } + + public R params(String key, File file) { + params.put(key, file); + return (R) this; + } + + public R params(String key, File file, String fileName) { + params.put(key, file, fileName); + return (R) this; + } + + public R params(String key, File file, String fileName, String contentType) { + params.put(key, file, fileName, contentType); + return (R) this; + } + + /** 通用的拼接请求头 */ + protected Request.Builder appendHeaders(Request.Builder requestBuilder) { + Headers.Builder headerBuilder = new Headers.Builder(); + ConcurrentHashMap headerMap = headers.headersMap; + if (headerMap.isEmpty()) return requestBuilder; + for (String key : headerMap.keySet()) { + headerBuilder.add(key, headerMap.get(key)); + } + requestBuilder.headers(headerBuilder.build()); + return requestBuilder; + } + + /** 根据不同的请求方式和参数,生成不同的RequestBody */ + public abstract RequestBody generateRequestBody(); + + /** 对请求body进行包装,用于回调上传进度 */ + public RequestBody wrapRequestBody(RequestBody requestBody, final AbsCallback callback) { + return new CountingRequestBody(requestBody, new CountingRequestBody.Listener() { + @Override + public void onRequestProgress(final long bytesWritten, final long contentLength) { + OkHttpUtils.getInstance().getDelivery().post(new Runnable() { + @Override + public void run() { + if (callback != null) + callback.upProgress(bytesWritten, contentLength, bytesWritten * 1.0f / contentLength); + } + }); + } + }); + } + + /** 根据不同的请求方式,将RequestBody转换成Request对象 */ + public abstract Request generateRequest(RequestBody requestBody); + + /** 根据当前的请求参数,生成对应的 Call 任务 */ + public Call generateCall(Request request) { + if (readTimeOut <= 0 && writeTimeOut <= 0 && connectTimeout <= 0 && certificates == null) { + return OkHttpUtils.getInstance().getOkHttpClient().newCall(request); + } else { + OkHttpClient.Builder newClientBuilder = OkHttpUtils.getInstance().getOkHttpClient().newBuilder(); + if (readTimeOut > 0) newClientBuilder.readTimeout(readTimeOut, TimeUnit.MILLISECONDS); + if (writeTimeOut > 0) + newClientBuilder.writeTimeout(writeTimeOut, TimeUnit.MILLISECONDS); + if (connectTimeout > 0) + newClientBuilder.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS); + if (certificates != null) + newClientBuilder.sslSocketFactory(HttpsUtils.getSslSocketFactory(certificates, null, null)); + return newClientBuilder.build().newCall(request); + } + } + + /** 阻塞方法,同步请求执行 */ + public Response execute() { + try { + RequestBody requestBody = generateRequestBody(); + final Request request = generateRequest(wrapRequestBody(requestBody, null)); + Call call = generateCall(request); + return call.execute(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + /** 非阻塞方法,异步请求,但是回调在子线程中执行 */ + public void execute(AbsCallback callback) { + if (callback == null) callback = AbsCallback.CALLBACK_DEFAULT; + + final AbsCallback finalCallback = callback; + finalCallback.onBefore(this); //请求执行前调用 (UI线程) + RequestBody requestBody = generateRequestBody(); + Request request = generateRequest(wrapRequestBody(requestBody, finalCallback)); + Call call = generateCall(request); + call.enqueue(new okhttp3.Callback() { + @Override + public void onFailure(Request request, IOException e) { + //请求失败,一般为url地址错误,网络错误等 + sendFailResultCallback(request, null, e, finalCallback); + } + + @Override + public void onResponse(Response response) throws IOException { + //响应失败,一般为服务器内部错误,或者找不到页面等 + if (response.code() >= 400 && response.code() <= 599) { + sendFailResultCallback(response.request(), response, null, finalCallback); + return; + } + + try { + //解析过程中抛出异常,一般为 json 格式错误,或者数据解析异常 + T t = (T) finalCallback.parseNetworkResponse(response); + sendSuccessResultCallback(t, response.request(), response, finalCallback); + } catch (Exception e) { + sendFailResultCallback(response.request(), response, e, finalCallback); + } + } + }); + } + + /** 失败回调,发送到主线程 */ + public void sendFailResultCallback(final Request request, final Response response, final Exception e, final AbsCallback callback) { + OkHttpUtils.getInstance().getDelivery().post(new Runnable() { + @Override + public void run() { + callback.onError(request, response, e); //请求失败回调 (UI线程) + callback.onAfter(null, request, response, e); //请求结束回调 (UI线程) + } + }); + } + + /** 成功回调,发送到主线程 */ + public void sendSuccessResultCallback(final T t, final Request request, final Response response, final AbsCallback callback) { + OkHttpUtils.getInstance().getDelivery().post(new Runnable() { + @Override + public void run() { + callback.onResponse(t); //请求成功回调 (UI线程) + callback.onAfter(t, request, response, null); //请求结束回调 (UI线程) + } + }); + } +} \ No newline at end of file diff --git a/library_okhttputils/src/main/java/com/lzy/okhttputils/request/CountingRequestBody.java b/library_okhttputils/src/main/java/com/lzy/okhttputils/request/CountingRequestBody.java new file mode 100644 index 00000000..89960320 --- /dev/null +++ b/library_okhttputils/src/main/java/com/lzy/okhttputils/request/CountingRequestBody.java @@ -0,0 +1,74 @@ +package com.lzy.okhttputils.request; + +import java.io.IOException; + +import okhttp3.MediaType; +import okhttp3.RequestBody; +import okio.Buffer; +import okio.BufferedSink; +import okio.ForwardingSink; +import okio.Okio; +import okio.Sink; + +/** + * Decorates an OkHttp request body to count the number of bytes written when writing it. Can + * decorate any request body, but is most useful for tracking the upload progress of large + * multipart requests. + * + * @author Leo Nikkilä + */ +public class CountingRequestBody extends RequestBody { + + protected RequestBody delegate; + protected Listener listener; + + protected CountingSink countingSink; + + public CountingRequestBody(RequestBody delegate, Listener listener) { + this.delegate = delegate; + this.listener = listener; + } + + @Override + public MediaType contentType() { + return delegate.contentType(); + } + + @Override + public long contentLength() { + try { + return delegate.contentLength(); + } catch (IOException e) { + e.printStackTrace(); + } + return -1; + } + + @Override + public void writeTo(BufferedSink sink) throws IOException { + countingSink = new CountingSink(sink); + BufferedSink bufferedSink = Okio.buffer(countingSink); + delegate.writeTo(bufferedSink); + bufferedSink.flush(); + } + + protected final class CountingSink extends ForwardingSink { + private long bytesWritten = 0; + + public CountingSink(Sink delegate) { + super(delegate); + } + + @Override + public void write(Buffer source, long byteCount) throws IOException { + super.write(source, byteCount); + bytesWritten += byteCount; + listener.onRequestProgress(bytesWritten, contentLength()); + } + + } + + public interface Listener { + void onRequestProgress(long bytesWritten, long contentLength); + } +} \ No newline at end of file diff --git a/library_okhttputils/src/main/java/com/lzy/okhttputils/request/GetRequest.java b/library_okhttputils/src/main/java/com/lzy/okhttputils/request/GetRequest.java new file mode 100644 index 00000000..06895701 --- /dev/null +++ b/library_okhttputils/src/main/java/com/lzy/okhttputils/request/GetRequest.java @@ -0,0 +1,56 @@ +package com.lzy.okhttputils.request; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.Map; + +import okhttp3.Request; +import okhttp3.RequestBody; + +/** + * ================================================ + * 作 者:廖子尧 + * 版 本:1.0 + * 创建日期:2016/1/12 + * 描 述:Get请求的实现类,注意需要传入本类的泛型 + * 修订历史: + * ================================================ + */ +public class GetRequest extends BaseRequest { + + public GetRequest(String url) { + super(url); + } + + @Override + public RequestBody generateRequestBody() { + return null; + } + + @Override + public Request generateRequest(RequestBody requestBody) { + Request.Builder requestBuilder = new Request.Builder(); + appendHeaders(requestBuilder); + url = createUrlFromParams(url, params.urlParamsMap); + return requestBuilder.get().url(url).tag(tag).build(); + } + + /** 将传递进来的参数拼接成 url */ + private String createUrlFromParams(String url, Map params) { + try { + StringBuilder sb = new StringBuilder(); + sb.append(url); + if (url.indexOf('&') > 0 || url.indexOf('?') > 0) sb.append("&"); + else sb.append("?"); + for (Map.Entry urlParams : params.entrySet()) { + String urlValue = URLEncoder.encode(urlParams.getValue(), "UTF-8"); + sb.append(urlParams.getKey()).append("=").append(urlValue).append("&"); + } + sb.deleteCharAt(sb.length() - 1); + return sb.toString(); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return url; + } +} \ No newline at end of file diff --git a/library_okhttputils/src/main/java/com/lzy/okhttputils/request/PostRequest.java b/library_okhttputils/src/main/java/com/lzy/okhttputils/request/PostRequest.java new file mode 100644 index 00000000..4e32b877 --- /dev/null +++ b/library_okhttputils/src/main/java/com/lzy/okhttputils/request/PostRequest.java @@ -0,0 +1,88 @@ +package com.lzy.okhttputils.request; + +import com.lzy.okhttputils.model.RequestParams; + +import java.io.File; +import java.util.Map; + +import okhttp3.FormBody; +import okhttp3.MediaType; +import okhttp3.MultipartBody; +import okhttp3.Request; +import okhttp3.RequestBody; + +/** + * ================================================ + * 作 者:廖子尧 + * 版 本:1.0 + * 创建日期:2016/1/12 + * 描 述:Post请求的实现类,注意需要传入本类的泛型 + * 修订历史: + * ================================================ + */ +public class PostRequest extends BaseRequest { + + public static final MediaType MEDIA_TYPE_PLAIN = MediaType.parse("text/plain;charset=utf-8"); + public static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json;charset=utf-8"); + public static final MediaType MEDIA_TYPE_STREAM = MediaType.parse("application/octet-stream"); + + private String content; + private MediaType mediaType; + + public PostRequest(String url) { + super(url); + } + + /** 注意使用该方法上传字符串会清空实体中其他所有的参数,头信息不清除 */ + public PostRequest content(String content) { + this.content = content; + return this; + } + + public PostRequest mediaType(MediaType mediaType) { + this.mediaType = mediaType; + return this; + } + + @Override + public RequestBody generateRequestBody() { + RequestBody requestBody; + if (content != null && mediaType != null) { + //post上传字符串数据 + requestBody = RequestBody.create(mediaType, content); + } else { + if (params.fileParamsMap.isEmpty()) { + //表单提交,没有文件 + FormBody.Builder bodyBuilder = new FormBody.Builder(); + for (String key : params.urlParamsMap.keySet()) { + bodyBuilder.add(key, params.urlParamsMap.get(key)); + } + requestBody = bodyBuilder.build(); + } else { + //表单提交,有文件 + MultipartBody.Builder multipartBodybuilder = new MultipartBody.Builder().setType(MultipartBody.FORM); + //拼接键值对 + if (!params.urlParamsMap.isEmpty()) { + for (String key : params.urlParamsMap.keySet()) { + multipartBodybuilder.addFormDataPart(key, params.urlParamsMap.get(key)); + } + } + //拼接文件 + for (Map.Entry entry : params.fileParamsMap.entrySet()) { + String contentType = entry.getValue().contentType; + RequestBody fileBody = RequestBody.create(MediaType.parse(contentType), entry.getValue().file); + multipartBodybuilder.addFormDataPart(entry.getKey(), entry.getValue().fileName, fileBody); + } + requestBody = multipartBodybuilder.build(); + } + } + return requestBody; + } + + @Override + public Request generateRequest(RequestBody requestBody) { + Request.Builder requestBuilder = new Request.Builder(); + appendHeaders(requestBuilder); + return requestBuilder.post(requestBody).url(url).tag(tag).build(); + } +} diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 00000000..a45efbd5 --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +include ':app', ':library_okhttputils'