() {
+ @Override
+ protected SimpleDateFormat initialValue() {
+ return new SimpleDateFormat("yyyy-MM-dd HH:mm");
+ }
+ };
+
+ /**
+ * 将字符串转位日期类型
+ *
+ * @param sdate
+ * @return
+ */
+ public static Date toDate(String sdate) {
+ return toDate(sdate, dateFormater.get());
+ }
+
+ public static Date toDate(String sdate, SimpleDateFormat dateFormater) {
+ try {
+ return dateFormater.parse(sdate);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public static String getDateString(Date date) {
+ return dateFormater.get().format(date);
+ }
+
+ public static String getDateString(String sdate) {
+ return dateFormat3.get().format(toDate(sdate));
+ }
+
+ /**
+ * 以友好的方式显示时间
+ *
+ * @param sdate
+ * @return
+ */
+ public static String friendly_time(String sdate) {
+ Date time = null;
+
+ if (TimeZoneUtil.isInEasternEightZones())
+ time = toDate(sdate);
+ else
+ time = TimeZoneUtil.transformTime(toDate(sdate),
+ TimeZone.getTimeZone("GMT+08"), TimeZone.getDefault());
+
+ if (time == null) {
+ return "Unknown";
+ }
+ String ftime = "";
+ Calendar cal = Calendar.getInstance();
+
+ // 判断是否是同一天
+ String curDate = dateFormater2.get().format(cal.getTime());
+ String paramDate = dateFormater2.get().format(time);
+ if (curDate.equals(paramDate)) {
+ int hour = (int) ((cal.getTimeInMillis() - time.getTime()) / 3600000);
+ if (hour == 0)
+ ftime = Math.max(
+ (cal.getTimeInMillis() - time.getTime()) / 60000, 1)
+ + "分钟前";
+ else
+ ftime = hour + "小时前";
+ return ftime;
+ }
+
+ long lt = time.getTime() / 86400000;
+ long ct = cal.getTimeInMillis() / 86400000;
+ int days = (int) (ct - lt);
+ if (days == 0) {
+ int hour = (int) ((cal.getTimeInMillis() - time.getTime()) / 3600000);
+ if (hour == 0)
+ ftime = Math.max(
+ (cal.getTimeInMillis() - time.getTime()) / 60000, 1)
+ + "分钟前";
+ else
+ ftime = hour + "小时前";
+ } else if (days == 1) {
+ ftime = "昨天";
+ } else if (days == 2) {
+ ftime = "前天 ";
+ } else if (days > 2 && days < 31) {
+ ftime = days + "天前";
+ } else if (days >= 31 && days <= 2 * 31) {
+ ftime = "一个月前";
+ } else if (days > 2 * 31 && days <= 3 * 31) {
+ ftime = "2个月前";
+ } else if (days > 3 * 31 && days <= 4 * 31) {
+ ftime = "3个月前";
+ } else {
+ ftime = dateFormater2.get().format(time);
+ }
+ return ftime;
+ }
+
+ public static String friendly_time2(String sdate) {
+ String res = "";
+ if (isEmpty(sdate))
+ return "";
+
+ String[] weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
+ String currentData = StringUtils.getDataTime("MM-dd");
+ int currentDay = toInt(currentData.substring(3));
+ int currentMoth = toInt(currentData.substring(0, 2));
+
+ int sMoth = toInt(sdate.substring(5, 7));
+ int sDay = toInt(sdate.substring(8, 10));
+ int sYear = toInt(sdate.substring(0, 4));
+ Date dt = new Date(sYear, sMoth - 1, sDay - 1);
+
+ if (sDay == currentDay && sMoth == currentMoth) {
+ res = "今天 / " + weekDays[getWeekOfDate(new Date())];
+ } else if (sDay == currentDay + 1 && sMoth == currentMoth) {
+ res = "昨天 / " + weekDays[(getWeekOfDate(new Date()) + 6) % 7];
+ } else {
+ if (sMoth < 10) {
+ res = "0";
+ }
+ res += sMoth + "/";
+ if (sDay < 10) {
+ res += "0";
+ }
+ res += sDay + " / " + weekDays[getWeekOfDate(dt)];
+ }
+
+ return res;
+ }
+
+
+ /**
+ * 智能格式化
+ */
+ public static String friendly_time3(String sdate) {
+ String res = "";
+ if (isEmpty(sdate))
+ return "";
+
+ Date date = StringUtils.toDate(sdate);
+ if (date == null)
+ return sdate;
+
+ SimpleDateFormat format = dateFormater2.get();
+
+ if (isToday(date.getTime())) {
+ format.applyPattern(isMorning(date.getTime()) ? "上午 hh:mm" : "下午 hh:mm");
+ res = format.format(date);
+ } else if (isYesterday(date.getTime())) {
+ format.applyPattern(isMorning(date.getTime()) ? "昨天 上午 hh:mm" : "昨天 下午 hh:mm");
+ res = format.format(date);
+ } else if (isCurrentYear(date.getTime())) {
+ format.applyPattern(isMorning(date.getTime()) ? "MM-dd 上午 hh:mm" : "MM-dd 下午 hh:mm");
+ res = format.format(date);
+ } else {
+ format.applyPattern(isMorning(date.getTime()) ? "yyyy-MM-dd 上午 hh:mm" : "yyyy-MM-dd 下午 hh:mm");
+ res = format.format(date);
+ }
+ return res;
+ }
+
+ /**
+ * @return 判断一个时间是不是上午
+ */
+ public static boolean isMorning(long when) {
+ android.text.format.Time time = new android.text.format.Time();
+ time.set(when);
+
+ int hour = time.hour;
+ return (hour >= 0) && (hour < 12);
+ }
+
+ /**
+ * @return 判断一个时间是不是今天
+ */
+ public static boolean isToday(long when) {
+ android.text.format.Time time = new android.text.format.Time();
+ time.set(when);
+
+ int thenYear = time.year;
+ int thenMonth = time.month;
+ int thenMonthDay = time.monthDay;
+
+ time.set(System.currentTimeMillis());
+ return (thenYear == time.year)
+ && (thenMonth == time.month)
+ && (thenMonthDay == time.monthDay);
+ }
+
+ /**
+ * @return 判断一个时间是不是昨天
+ */
+ public static boolean isYesterday(long when) {
+ android.text.format.Time time = new android.text.format.Time();
+ time.set(when);
+
+ int thenYear = time.year;
+ int thenMonth = time.month;
+ int thenMonthDay = time.monthDay;
+
+ time.set(System.currentTimeMillis());
+ return (thenYear == time.year)
+ && (thenMonth == time.month)
+ && (time.monthDay - thenMonthDay == 1);
+ }
+
+ /**
+ * @return 判断一个时间是不是今年
+ */
+ public static boolean isCurrentYear(long when) {
+ android.text.format.Time time = new android.text.format.Time();
+ time.set(when);
+
+ int thenYear = time.year;
+
+ time.set(System.currentTimeMillis());
+ return (thenYear == time.year);
+ }
+
+ /**
+ * 获取当前日期是星期几
+ *
+ * @param dt
+ * @return 当前日期是星期几
+ */
+ public static int getWeekOfDate(Date dt) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(dt);
+ int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
+ if (w < 0)
+ w = 0;
+ return w;
+ }
+
+ /**
+ * 判断给定字符串时间是否为今日
+ *
+ * @param sdate
+ * @return boolean
+ */
+ public static boolean isToday(String sdate) {
+ boolean b = false;
+ Date time = toDate(sdate);
+ Date today = new Date();
+ if (time != null) {
+ String nowDate = dateFormater2.get().format(today);
+ String timeDate = dateFormater2.get().format(time);
+ if (nowDate.equals(timeDate)) {
+ b = true;
+ }
+ }
+ return b;
+ }
+
+ /**
+ * 是否是相同的一天
+ * @param sDate1 sDate1
+ * @param sDate2 sDate2
+ * @return
+ */
+ public static boolean isSameDay(String sDate1,String sDate2){
+ if(TextUtils.isEmpty(sDate1) || TextUtils.isEmpty(sDate2)){
+ return false;
+ }
+ boolean b = false;
+ Date date1 = toDate(sDate1);
+ Date date2 = toDate(sDate2);
+ if(date1!= null && date2 != null){
+ String d1 = dateFormater2.get().format(date1);
+ String d2 = dateFormater2.get().format(date2);
+ if (d1.equals(d2)) {
+ b = true;
+ }
+ }
+ return b;
+ }
+
+ /**
+ * 返回long类型的今天的日期
+ *
+ * @return
+ */
+ public static long getToday() {
+ Calendar cal = Calendar.getInstance();
+ String curDate = dateFormater2.get().format(cal.getTime());
+ curDate = curDate.replace("-", "");
+ return Long.parseLong(curDate);
+ }
+
+ public static String getCurTimeStr() {
+ Calendar cal = Calendar.getInstance();
+ String curDate = dateFormater.get().format(cal.getTime());
+ return curDate;
+ }
+
+ /***
+ * 计算两个时间差,返回的是的秒s
+ *
+ * @param dete1
+ * @param date2
+ * @return
+ * @author 火蚁 2015-2-9 下午4:50:06
+ */
+ public static long calDateDifferent(String dete1, String date2) {
+
+ long diff = 0;
+
+ Date d1 = null;
+ Date d2 = null;
+
+ try {
+ d1 = dateFormater.get().parse(dete1);
+ d2 = dateFormater.get().parse(date2);
+
+ // 毫秒ms
+ diff = d2.getTime() - d1.getTime();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return diff / 1000;
+ }
+
+ /**
+ * 判断给定字符串是否空白串。 空白串是指由空格、制表符、回车符、换行符组成的字符串 若输入字符串为null或空字符串,返回true
+ *
+ * @param input
+ * @return boolean
+ */
+ public static boolean isEmpty(String input) {
+ if (input == null || "".equals(input))
+ return true;
+
+ for (int i = 0; i < input.length(); i++) {
+ char c = input.charAt(i);
+ if (c != ' ' && c != '\t' && c != '\r' && c != '\n') {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * 判断是不是一个合法的电子邮件地址
+ *
+ * @param email
+ * @return
+ */
+ public static boolean isEmail(String email) {
+ if (email == null || email.trim().length() == 0)
+ return false;
+ return emailer.matcher(email).matches();
+ }
+
+ /**
+ * 判断一个url是否为图片url
+ *
+ * @param url
+ * @return
+ */
+ public static boolean isImgUrl(String url) {
+ if (url == null || url.trim().length() == 0)
+ return false;
+ return IMG_URL.matcher(url).matches();
+ }
+
+ /**
+ * 判断是否为一个合法的url地址
+ *
+ * @param str
+ * @return
+ */
+ public static boolean isUrl(String str) {
+ if (str == null || str.trim().length() == 0)
+ return false;
+ return URL.matcher(str).matches();
+ }
+
+ /**
+ * 字符串转整数
+ *
+ * @param str
+ * @param defValue
+ * @return
+ */
+ public static int toInt(String str, int defValue) {
+ try {
+ return Integer.parseInt(str);
+ } catch (Exception e) {
+ }
+ return defValue;
+ }
+
+ /**
+ * 对象转整数
+ *
+ * @param obj
+ * @return 转换异常返回 0
+ */
+ public static int toInt(Object obj) {
+ if (obj == null)
+ return 0;
+ return toInt(obj.toString(), 0);
+ }
+
+ /**
+ * 对象转整数
+ *
+ * @param obj
+ * @return 转换异常返回 0
+ */
+ public static long toLong(String obj) {
+ try {
+ return Long.parseLong(obj);
+ } catch (Exception e) {
+ }
+ return 0;
+ }
+
+ /**
+ * 字符串转布尔值
+ *
+ * @param b
+ * @return 转换异常返回 false
+ */
+ public static boolean toBool(String b) {
+ try {
+ return Boolean.parseBoolean(b);
+ } catch (Exception e) {
+ }
+ return false;
+ }
+
+ public static String getString(String s) {
+ return s == null ? "" : s;
+ }
+
+ /**
+ * 将一个InputStream流转换成字符串
+ *
+ * @param is
+ * @return
+ */
+ public static String toConvertString(InputStream is) {
+ StringBuffer res = new StringBuffer();
+ InputStreamReader isr = new InputStreamReader(is);
+ BufferedReader read = new BufferedReader(isr);
+ try {
+ String line;
+ line = read.readLine();
+ while (line != null) {
+ res.append(line + " ");
+ line = read.readLine();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ if (null != isr) {
+ isr.close();
+ isr.close();
+ }
+ if (null != read) {
+ read.close();
+ read = null;
+ }
+ if (null != is) {
+ is.close();
+ is = null;
+ }
+ } catch (IOException e) {
+ }
+ }
+ return res.toString();
+ }
+
+ /***
+ * 截取字符串
+ *
+ * @param start 从那里开始,0算起
+ * @param num 截取多少个
+ * @param str 截取的字符串
+ * @return
+ */
+ public static String getSubString(int start, int num, String str) {
+ if (str == null) {
+ return "";
+ }
+ int leng = str.length();
+ if (start < 0) {
+ start = 0;
+ }
+ if (start > leng) {
+ start = leng;
+ }
+ if (num < 0) {
+ num = 1;
+ }
+ int end = start + num;
+ if (end > leng) {
+ end = leng;
+ }
+ return str.substring(start, end);
+ }
+
+ /**
+ * 获取当前时间为每年第几周
+ *
+ * @return
+ */
+ public static int getWeekOfYear() {
+ return getWeekOfYear(new Date());
+ }
+
+ /**
+ * 获取当前时间为每年第几周
+ *
+ * @param date
+ * @return
+ */
+ public static int getWeekOfYear(Date date) {
+ Calendar c = Calendar.getInstance();
+ c.setFirstDayOfWeek(Calendar.MONDAY);
+ c.setTime(date);
+ int week = c.get(Calendar.WEEK_OF_YEAR) - 1;
+ week = week == 0 ? 52 : week;
+ return week > 0 ? week : 1;
+ }
+
+ public static int[] getCurrentDate() {
+ int[] dateBundle = new int[3];
+ String[] temp = getDataTime("yyyy-MM-dd").split("-");
+
+ for (int i = 0; i < 3; i++) {
+ try {
+ dateBundle[i] = Integer.parseInt(temp[i]);
+ } catch (Exception e) {
+ dateBundle[i] = 0;
+ }
+ }
+ return dateBundle;
+ }
+
+ /**
+ * 返回当前系统时间
+ */
+ public static String getDataTime(String format) {
+ SimpleDateFormat df = new SimpleDateFormat(format);
+ return df.format(new Date());
+ }
+
+}
diff --git a/src/MyApplication/app/src/main/java/com/example/administrator/myapplication/utils/TimeZoneUtil.java b/src/MyApplication/app/src/main/java/com/example/administrator/myapplication/utils/TimeZoneUtil.java
new file mode 100644
index 0000000..9c1fbe0
--- /dev/null
+++ b/src/MyApplication/app/src/main/java/com/example/administrator/myapplication/utils/TimeZoneUtil.java
@@ -0,0 +1,40 @@
+package com.example.administrator.myapplication.utils;
+
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * @author HuangWenwei
+ *
+ * @date 2014年10月9日
+ */
+public class TimeZoneUtil {
+
+ /**
+ * 判断用户的设备时区是否为东八区(中国) 2014年7月31日
+ * @return
+ */
+ public static boolean isInEasternEightZones() {
+ boolean defaultVaule = true;
+ if (TimeZone.getDefault() == TimeZone.getTimeZone("GMT+08"))
+ defaultVaule = true;
+ else
+ defaultVaule = false;
+ return defaultVaule;
+ }
+
+ /**
+ * 根据不同时区,转换时间 2014年7月31日
+ * @param time
+ * @return
+ */
+ public static Date transformTime(Date date, TimeZone oldZone, TimeZone newZone) {
+ Date finalDate = null;
+ if (date != null) {
+ int timeOffset = oldZone.getOffset(date.getTime())
+ - newZone.getOffset(date.getTime());
+ finalDate = new Date(date.getTime() - timeOffset);
+ }
+ return finalDate;
+ }
+}
diff --git a/src/MyApplication/app/src/main/java/com/example/administrator/myapplication/webview/APIWebViewActivity.java b/src/MyApplication/app/src/main/java/com/example/administrator/myapplication/webview/APIWebViewActivity.java
new file mode 100644
index 0000000..6ea72d5
--- /dev/null
+++ b/src/MyApplication/app/src/main/java/com/example/administrator/myapplication/webview/APIWebViewActivity.java
@@ -0,0 +1,385 @@
+package com.example.administrator.myapplication.webview;
+
+import android.annotation.TargetApi;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.net.http.SslError;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.DownloadListener;
+import android.webkit.JavascriptInterface;
+import android.webkit.JsPromptResult;
+import android.webkit.JsResult;
+import android.webkit.SslErrorHandler;
+import android.webkit.ValueCallback;
+import android.webkit.WebChromeClient;
+import android.webkit.WebResourceError;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebResourceResponse;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.Toast;
+
+import com.example.administrator.myapplication.R;
+
+/**
+ * 演示WebView中的Api说明、js交互的方法,还有注意事项
+ *
+ * 1、内存泄漏防备
+ * 2、配置webView
+ * 3、页面加载开始,错误,拦截请求,接受Error等
+ * 4、页面加载进度,title,图标,js弹框等
+ * 5、js交互与安全
+ */
+public class APIWebViewActivity extends AppCompatActivity implements View.OnClickListener {
+
+ FrameLayout mRootLayout;
+ WebView mWebView;
+ Button mButton;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_api_webview);
+
+ findViewById(R.id.call_js_function).setOnClickListener(this);
+
+ //添加webView到布局中
+ addWebViewToLayout();
+
+ //set webView Setting
+ setWebView();
+
+ //set webView Client
+ setWebClient();
+
+ //set webView chrome
+ setWebViewChromeClient();
+
+ //load web
+ loadUrl();
+
+ }
+
+ /**
+ * 主动清空销毁来避免内存泄漏
+ */
+ @Override
+ protected void onDestroy() {
+ if (mWebView != null) {
+ mWebView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
+ mWebView.clearHistory();
+ ((ViewGroup) mWebView.getParent()).removeView(mWebView);
+ mWebView.destroy();
+ mWebView = null;
+ }
+ super.onDestroy();
+ }
+
+
+ /**
+ * 1、不在xml中定义Webview,而是在需要的时候在Activity中创建
+ * 使用getApplicationgContext(),避免内存泄漏。
+ *
+ * 2、当然,你也可以配置webView所在Activity,
+ * 在AndroidManifest中的进程为:android:process=":remote"
+ * 避免泄漏影响主进程
+ **/
+ void addWebViewToLayout() {
+ mRootLayout = (FrameLayout) findViewById(R.id.js_root_layout);
+ FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+ mWebView = new WebView(getApplicationContext());
+ mWebView.setLayoutParams(params);
+ mRootLayout.addView(mWebView);
+ }
+
+
+ /**
+ * 配置webView
+ */
+ void setWebView() {
+ //声明WebSettings子类
+ WebSettings webSettings = mWebView.getSettings();
+
+ //支持Javascript交互
+ webSettings.setJavaScriptEnabled(true);
+
+
+ //设置自适应屏幕,两者合用
+ webSettings.setUseWideViewPort(true); //将图片调整到适合webview的大小
+ webSettings.setLoadWithOverviewMode(true); // 缩放至屏幕的大小
+
+ //缩放操作
+ webSettings.setSupportZoom(true); //支持缩放,默认为true。是下面那个的前提。
+ webSettings.setBuiltInZoomControls(true); //设置内置的缩放控件。若为false,则该WebView不可缩放
+ webSettings.setDisplayZoomControls(false); //隐藏原生的缩放控件
+
+ //其他细节操作
+ //webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //关闭webview中缓存
+ webSettings.setAllowFileAccess(true); //设置可以访问文件
+
+ //对于不需要使用 file 协议的应用,禁用 file 协议;防止文件泄密,file协议即是file://
+ //webSettings.setAllowFileAccess(false);
+ //webSettings.setAllowFileAccessFromFileURLs(false);
+ //webSettings.setAllowUniversalAccessFromFileURLs(false);
+
+
+
+ webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口
+ webSettings.setLoadsImagesAutomatically(true); //支持自动加载图片
+ webSettings.setDefaultTextEncodingName("utf-8");//设置编码格式
+
+ mWebView.setDownloadListener(new DownloadListener() {
+ @Override
+ public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
+ //网页中触发下载动作
+ }
+ });
+
+ //增加js交互接口
+ mWebView.addJavascriptInterface(new JsCallAndroidInterface(), "JSCallBackInterface");
+ }
+
+ /**
+ * 设置webView的Client,如页面加载开始,错误,拦截请求,接受Error等
+ */
+ void setWebClient() {
+ mWebView.setWebViewClient(new WebViewClient() {
+
+ //拦截页面中的url加载,21以下的
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, String url) {
+ if (resolveShouldLoadLogic(url)) {
+ return true;
+ }
+ return super.shouldOverrideUrlLoading(view, url);
+ }
+
+ //拦截页面中的url加载,21以上的
+ @TargetApi(21)
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
+ if (resolveShouldLoadLogic(request.getUrl().toString())) {
+ return true;
+ }
+ return super.shouldOverrideUrlLoading(view, request);
+ }
+
+ //页面开始加载
+ @Override
+ public void onPageStarted(WebView view, String url, Bitmap favicon) {
+ super.onPageStarted(view, url, favicon);
+ }
+
+ //页面加载完成
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ super.onPageFinished(view, url);
+ }
+
+ //页面加载每一个资源,如图片
+ @Override
+ public void onLoadResource(WebView view, String url) {
+ super.onLoadResource(view, url);
+ }
+
+ //监听WebView发出的请求并做相应的处理
+ //浏览器的渲染以及资源加载都是在一个线程中,如果在shouldInterceptRequest处理时间过长,WebView界面就会阻塞
+ //21以下的
+ @Override
+ public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
+ return super.shouldInterceptRequest(view, url);
+ }
+
+ //监听WebView发出的请求并做相应的处理
+ //浏览器的渲染以及资源加载都是在一个线程中,如果在shouldInterceptRequest处理时间过长,WebView界面就会阻塞
+ //21以上的
+ @Override
+ public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
+ return super.shouldInterceptRequest(view, request);
+ }
+
+ //页面加载出现错误,23以下的
+ @Override
+ public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
+ super.onReceivedError(view, errorCode, description, failingUrl);
+ switch (errorCode) {
+ case 404:
+ //view.loadUrl("加载一个错误页面提示,优化体验");
+ break;
+ }
+ }
+
+ //页面加载出现错误,23以上的
+ @TargetApi(23)
+ @Override
+ public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
+ super.onReceivedError(view, request, error);
+ switch (error.getErrorCode()) {
+ case 404:
+ //view.loadUrl("加载一个错误页面提示,优化体验");
+ break;
+ }
+
+ }
+
+ //https错误
+ @Override
+ public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
+ super.onReceivedSslError(view, handler, error);
+ }
+ });
+ }
+
+ /**
+ * 设置webView的辅助功能,如页面加载进度,title,图标,js弹框等
+ */
+ void setWebViewChromeClient() {
+ mWebView.setWebChromeClient(new WebChromeClient() {
+
+ //页面加载进度
+ @Override
+ public void onProgressChanged(WebView view, int newProgress) {
+ super.onProgressChanged(view, newProgress);
+ }
+
+ //获取标题
+ @Override
+ public void onReceivedTitle(WebView view, String title) {
+ super.onReceivedTitle(view, title);
+ }
+
+ //获取图标
+ @Override
+ public void onReceivedIcon(WebView view, Bitmap icon) {
+ super.onReceivedIcon(view, icon);
+ }
+
+ //是否支持页面中的js警告弹出框
+ @Override
+ public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
+
+ Toast.makeText(APIWebViewActivity.this, message, Toast.LENGTH_SHORT).show();
+
+ return super.onJsAlert(view, url, message, result);
+ }
+
+ //是否支持页面中的js确定弹出框
+ @Override
+ public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
+ return super.onJsConfirm(view, url, message, result);
+ }
+
+ //是否支持页面中的js输入弹出框
+ @Override
+ public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
+ /**
+ * 有时候,为了安全考虑,js的参数回调,会通过这类地方回调回来,然后不弹出框。
+ */
+ if(resolveJSPrompt(message)) {
+ return true;
+ }
+ return super.onJsPrompt(view, url, message, defaultValue, result);
+
+ }
+ });
+ }
+
+ /**
+ * 加载url
+ */
+ void loadUrl() {
+ // 格式规定为:file:///android_asset/文件名.html
+ mWebView.loadUrl("file:///android_asset/localHtml.html");
+ //方式1. 加载远程网页:
+ //mWebView.loadUrl("http://www.baidu.com/");
+ //方式2:加载asset的html页面
+ //mWebView.loadUrl("file:///android_asset/localHtml.html");
+ //方式3:加载手机SD的html页面
+ //mWebView.loadUrl("file:///mnt/sdcard/database/taobao.html");
+ }
+
+ /**
+ * 执行网页中的js方法
+ */
+ void callJsFunction() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback() {
+ @Override
+ public void onReceiveValue(String value) {
+ //接受返回值
+ }
+ });
+ } else {
+ mWebView.loadUrl("javascript:callJS()");
+ }
+ }
+
+ /**
+ * js与web交互1
+ * js 与 原生交互接口
+ */
+ private class JsCallAndroidInterface {
+
+ //@JavascriptInterface注解方法,js端调用,4.2以后安全
+ //4.2以前,当JS拿到Android这个对象后,就可以调用这个Android对象中所有的方法,包括系统类(java.lang.Runtime 类),从而进行任意代码执行。
+ @JavascriptInterface
+ public void callback(String msg) {
+ Toast.makeText(APIWebViewActivity.this, "JS方法回调到web了 :" + msg, Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ /**
+ * js与web交互2
+ * 通过 shouldOverrideUrlLoading 与 js交互
+ */
+ private boolean resolveShouldLoadLogic(String url) {
+ Uri uri = Uri.parse(url);
+ //解析协议
+ if (uri.getScheme().equals("js")) {
+ if (uri.getAuthority().equals("Authority")) {
+ //你还可以继续接续参数
+ //Set collection = uri.getQueryParameterNames();
+ Toast.makeText(APIWebViewActivity.this, "JS 2方法回调到web了", Toast.LENGTH_SHORT).show();
+
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * js与web交互3
+ * 通过 onJsPrompt 与 js交互
+ */
+ private boolean resolveJSPrompt(String message) {
+ Uri uri = Uri.parse(message);
+ if ( uri.getScheme().equals("js")) {
+ if (uri.getAuthority().equals("Authority")) {
+
+ //Set collection = uri.getQueryParameterNames();
+ //参数result:代表消息框的返回值(输入值)
+ //result.confirm("JS 3方法回调到web");
+ Toast.makeText(APIWebViewActivity.this, "JS 3方法回调到web了", Toast.LENGTH_SHORT).show();
+ }
+ return true;
+ }
+ return false;
+ }
+
+
+ @Override
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.call_js_function:
+ callJsFunction();
+ break;
+ }
+ }
+}
diff --git a/src/MyApplication/app/src/main/java/com/example/administrator/myapplication/webview/WebActivity.java b/src/MyApplication/app/src/main/java/com/example/administrator/myapplication/webview/WebActivity.java
new file mode 100644
index 0000000..52f6c81
--- /dev/null
+++ b/src/MyApplication/app/src/main/java/com/example/administrator/myapplication/webview/WebActivity.java
@@ -0,0 +1,120 @@
+package com.example.administrator.myapplication.webview;
+
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.webkit.WebResourceError;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.Toast;
+
+import com.example.administrator.myapplication.R;
+import com.shuyu.action.web.ActionSelectListener;
+import com.shuyu.action.web.CustomActionWebView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class WebActivity extends AppCompatActivity {
+
+
+ View mLadingView;
+ CustomActionWebView mCustomActionWebView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_web);
+
+ mLadingView = findViewById(R.id.loadingView);
+ mCustomActionWebView = (CustomActionWebView)findViewById(R.id.customActionWebView);
+
+
+ List list = new ArrayList<>();
+ list.add("复制");
+ list.add("粘贴");
+ list.add("一键嗖藏");
+
+ mCustomActionWebView.setWebViewClient(new CustomWebViewClient());
+
+ //设置item
+ mCustomActionWebView.setActionList(list);
+
+ //链接js注入接口,使能选中返回数据
+ mCustomActionWebView.linkJSInterface();
+
+ mCustomActionWebView.getSettings().setBuiltInZoomControls(true);
+ mCustomActionWebView.getSettings().setDisplayZoomControls(false);
+ //使用javascript
+ mCustomActionWebView.getSettings().setJavaScriptEnabled(true);
+ mCustomActionWebView.getSettings().setDomStorageEnabled(true);
+
+
+ //增加点击回调
+ mCustomActionWebView.setActionSelectListener(new ActionSelectListener() {
+ @Override
+ public void onClick(String title, String selectText) {
+ if(title.equals("一键嗖藏")) {
+ Toast.makeText(WebActivity.this, "Click Item: " + title + "。\n\nValue: " + selectText, Toast.LENGTH_LONG).show();
+
+ return;
+ }
+ //System.out.println(title + selectText);
+ Toast.makeText(WebActivity.this, "Click Item: " + title + "。\n\nValue: " + selectText, Toast.LENGTH_LONG).show();
+ }
+ });
+
+ //加载url
+ mCustomActionWebView.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ mCustomActionWebView.loadUrl("https://www.cnblogs.com/joy99/p/6343237.html");
+ }
+ }, 1000);
+ }
+
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if(mCustomActionWebView != null) {
+ mCustomActionWebView.dismissAction();
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ }
+
+ private class CustomWebViewClient extends WebViewClient {
+
+ private boolean mLastLoadFailed = false;
+
+ @Override
+ public void onPageFinished(WebView webView, String url) {
+ super.onPageFinished(webView, url);
+ if (!mLastLoadFailed) {
+ CustomActionWebView customActionWebView = (CustomActionWebView) webView;
+ customActionWebView.linkJSInterface();
+ mLadingView.setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ public void onPageStarted(WebView webView, String url, Bitmap favicon) {
+ super.onPageStarted(webView, url, favicon);
+ }
+
+ @Override
+ public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
+ super.onReceivedError(view, request, error);
+ mLastLoadFailed = true;
+ mLadingView.setVisibility(View.GONE);
+ }
+ }
+
+}
diff --git a/src/MyApplication/app/src/main/res/drawable/app_bar_menu.png b/src/MyApplication/app/src/main/res/drawable/app_bar_menu.png
new file mode 100644
index 0000000000000000000000000000000000000000..bdeecd4ff6e7f423650e364e48cbe5553ca038ed
GIT binary patch
literal 84
zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+0wn(&ce?|mq&;06Lp07OCrB)LU@zAYaHT=I
hZ&&7lJ1(LO3_8~)HE)oXbOtJ8@O1TaS?83{1OPiC7We=F
literal 0
HcmV?d00001
diff --git a/src/MyApplication/app/src/main/res/drawable/app_bar_search.png b/src/MyApplication/app/src/main/res/drawable/app_bar_search.png
new file mode 100644
index 0000000000000000000000000000000000000000..3227a753974547fbe85b3d0621c2e1ec9ce7a2fd
GIT binary patch
literal 225
zcmV<703QE|P)5>2
zA+kXM6adhBvnHsL1qeS_ie?3>75qXJu?k~`9lR*WznL-PC+P_sf?(b=FF7aT>$FX*
z?acJzGe1u54hp5KQPgQW`O}Xl9a}eps4{Waj~6XRo2asOh&SdgQDvuyH>S#{GE?fr
zi?mlnm7c4uRy;|+7)G6uo1?j@JI`gLlnO&*tYkEiR#?htA}z6y(L`GK*NtXU
bH@@rv%_oI*x^sKP00000NkvXXu0mjf$lzMc
literal 0
HcmV?d00001
diff --git a/src/MyApplication/app/src/main/res/layout/activity_api_webview.xml b/src/MyApplication/app/src/main/res/layout/activity_api_webview.xml
new file mode 100644
index 0000000..ea58c8b
--- /dev/null
+++ b/src/MyApplication/app/src/main/res/layout/activity_api_webview.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/MyApplication/app/src/main/res/layout/activity_float_window.xml b/src/MyApplication/app/src/main/res/layout/activity_float_window.xml
new file mode 100644
index 0000000..67c578f
--- /dev/null
+++ b/src/MyApplication/app/src/main/res/layout/activity_float_window.xml
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/src/MyApplication/app/src/main/res/layout/activity_web.xml b/src/MyApplication/app/src/main/res/layout/activity_web.xml
new file mode 100644
index 0000000..fd7f2dc
--- /dev/null
+++ b/src/MyApplication/app/src/main/res/layout/activity_web.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
diff --git a/src/MyApplication/app/src/main/res/layout/activity_welcome.xml b/src/MyApplication/app/src/main/res/layout/activity_welcome.xml
index 12668e0..f62012c 100644
--- a/src/MyApplication/app/src/main/res/layout/activity_welcome.xml
+++ b/src/MyApplication/app/src/main/res/layout/activity_welcome.xml
@@ -32,9 +32,9 @@
android:text="@string/slogan"
android:gravity="center"
android:id="@+id/textView4"
+ android:layout_marginBottom="89dp"
android:layout_above="@+id/textView5"
- android:layout_centerHorizontal="true"
- android:layout_marginBottom="87dp"/>
+ android:layout_centerHorizontal="true"/>
diff --git a/src/MyApplication/app/src/main/res/layout/app_bar_main.xml b/src/MyApplication/app/src/main/res/layout/app_bar_main.xml
index 6feda2e..0f8a02c 100644
--- a/src/MyApplication/app/src/main/res/layout/app_bar_main.xml
+++ b/src/MyApplication/app/src/main/res/layout/app_bar_main.xml
@@ -7,20 +7,6 @@
android:fitsSystemWindows="true"
tools:context="com.example.administrator.myapplication.ui.MainActivity">
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/MyApplication/app/src/main/res/xml/provider_paths.xml b/src/MyApplication/app/src/main/res/xml/provider_paths.xml
new file mode 100644
index 0000000..ffa74ab
--- /dev/null
+++ b/src/MyApplication/app/src/main/res/xml/provider_paths.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/MyApplication/library/.gitignore b/src/MyApplication/library/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/src/MyApplication/library/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/src/MyApplication/library/build.gradle b/src/MyApplication/library/build.gradle
new file mode 100644
index 0000000..59e1436
--- /dev/null
+++ b/src/MyApplication/library/build.gradle
@@ -0,0 +1,24 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 25
+ buildToolsVersion "25.0.3"
+
+ defaultConfig {
+ minSdkVersion 17
+ targetSdkVersion 25
+ versionCode 1
+ versionName "1.0"
+
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ compile fileTree(dir: 'libs', include: ['*.jar'])
+}
diff --git a/src/MyApplication/library/proguard-rules.pro b/src/MyApplication/library/proguard-rules.pro
new file mode 100644
index 0000000..6defe3b
--- /dev/null
+++ b/src/MyApplication/library/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /Users/guoshuyu/Library/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 *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/src/MyApplication/library/src/main/AndroidManifest.xml b/src/MyApplication/library/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..faf8e20
--- /dev/null
+++ b/src/MyApplication/library/src/main/AndroidManifest.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/src/MyApplication/library/src/main/java/com/shuyu/action/web/ActionSelectListener.java b/src/MyApplication/library/src/main/java/com/shuyu/action/web/ActionSelectListener.java
new file mode 100644
index 0000000..97d6170
--- /dev/null
+++ b/src/MyApplication/library/src/main/java/com/shuyu/action/web/ActionSelectListener.java
@@ -0,0 +1,9 @@
+package com.shuyu.action.web;
+
+/**
+ * Created by guoshuyu on 2017/6/17.
+ */
+
+public interface ActionSelectListener {
+ void onClick(String title, String selectText);
+}
diff --git a/src/MyApplication/library/src/main/java/com/shuyu/action/web/CustomActionWebView.java b/src/MyApplication/library/src/main/java/com/shuyu/action/web/CustomActionWebView.java
new file mode 100644
index 0000000..f9dc992
--- /dev/null
+++ b/src/MyApplication/library/src/main/java/com/shuyu/action/web/CustomActionWebView.java
@@ -0,0 +1,159 @@
+package com.shuyu.action.web;
+
+import android.content.Context;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.ActionMode;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.webkit.JavascriptInterface;
+import android.webkit.WebView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class CustomActionWebView extends WebView {
+
+ static String TAG = "CustomActionWebView";
+
+ ActionMode mActionMode;
+
+ List mActionList = new ArrayList<>();
+
+ ActionSelectListener mActionSelectListener;
+
+ public CustomActionWebView(Context context) {
+ super(context);
+ }
+
+ public CustomActionWebView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public CustomActionWebView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+
+ /**
+ * 处理item,处理点击
+ * @param actionMode
+ */
+ private ActionMode resolveActionMode(ActionMode actionMode) {
+ if (actionMode != null) {
+ final Menu menu = actionMode.getMenu();
+ mActionMode = actionMode;
+ menu.clear();
+ for (int i = 0; i < mActionList.size(); i++) {
+ menu.add(mActionList.get(i));
+ }
+ for (int i = 0; i < menu.size(); i++) {
+ MenuItem menuItem = menu.getItem(i);
+ menuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ getSelectedData((String) item.getTitle());
+ releaseAction();
+ return true;
+ }
+ });
+ }
+ }
+ mActionMode = actionMode;
+ return actionMode;
+ }
+
+ @Override
+ public ActionMode startActionMode(ActionMode.Callback callback) {
+ ActionMode actionMode = super.startActionMode(callback);
+ return resolveActionMode(actionMode);
+ }
+
+ @Override
+ public ActionMode startActionMode(ActionMode.Callback callback, int type) {
+ ActionMode actionMode = super.startActionMode(callback, type);
+ return resolveActionMode(actionMode);
+ }
+
+ private void releaseAction() {
+ if (mActionMode != null) {
+ mActionMode.finish();
+ mActionMode = null;
+ }
+ }
+
+ /**
+ * 点击的时候,获取网页中选择的文本,回掉到原生中的js接口
+ * @param title 传入点击的item文本,一起通过js返回给原生接口
+ */
+ private void getSelectedData(String title) {
+
+ String js = "(function getSelectedText() {" +
+ "var txt;" +
+ "var title = \"" + title + "\";" +
+ "if (window.getSelection) {" +
+ "txt = window.getSelection().toString();" +
+ "} else if (window.document.getSelection) {" +
+ "txt = window.document.getSelection().toString();" +
+ "} else if (window.document.selection) {" +
+ "txt = window.document.selection.createRange().text;" +
+ "}" +
+ "JSInterface.callback(txt,title);" +
+ "})()";
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ evaluateJavascript("javascript:" + js, null);
+ //System.out.println(123);
+ } else {
+ loadUrl("javascript:" + js);
+ //System.out.println(456);
+ }
+ }
+
+ public void linkJSInterface() {
+ addJavascriptInterface(new ActionSelectInterface(this), "JSInterface");
+ }
+
+ /**
+ * 设置弹出action列表
+ * @param actionList
+ */
+ public void setActionList(List actionList) {
+ mActionList = actionList;
+ }
+
+ /**
+ * 设置点击回掉
+ * @param actionSelectListener
+ */
+ public void setActionSelectListener(ActionSelectListener actionSelectListener) {
+ this.mActionSelectListener = actionSelectListener;
+ }
+
+ /**
+ * 隐藏消失Action
+ */
+ public void dismissAction() {
+ releaseAction();
+ }
+
+
+ /**
+ * js选中的回掉接口
+ */
+ private class ActionSelectInterface {
+
+ CustomActionWebView mContext;
+
+ ActionSelectInterface(CustomActionWebView c) {
+ mContext = c;
+ }
+
+ @JavascriptInterface
+ public void callback(final String value, final String title) {
+ if(mActionSelectListener != null) {
+ mActionSelectListener.onClick(title, value);
+ }
+ }
+ }
+}
diff --git a/src/MyApplication/library/src/main/res/values/strings.xml b/src/MyApplication/library/src/main/res/values/strings.xml
new file mode 100644
index 0000000..49fc91e
--- /dev/null
+++ b/src/MyApplication/library/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ library
+
diff --git a/src/MyApplication/libs/BmobSDKDemo_v3.6.0/BmobDemo/app/src/main/java/cn/bmob/sdkdemo/autoupdate/ActAutoUpdate.java b/src/MyApplication/libs/BmobSDKDemo_v3.6.0/BmobDemo/app/src/main/java/cn/bmob/sdkdemo/autoupdate/ActAutoUpdate.java
index 411c8c8..beefd92 100644
--- a/src/MyApplication/libs/BmobSDKDemo_v3.6.0/BmobDemo/app/src/main/java/cn/bmob/sdkdemo/autoupdate/ActAutoUpdate.java
+++ b/src/MyApplication/libs/BmobSDKDemo_v3.6.0/BmobDemo/app/src/main/java/cn/bmob/sdkdemo/autoupdate/ActAutoUpdate.java
@@ -26,6 +26,7 @@ public class ActAutoUpdate extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
+ // TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
diff --git a/src/MyApplication/libs/BmobSDKDemo_v3.6.0/BmobDemo/app/src/main/java/cn/bmob/sdkdemo/push/ActBmobPush.java b/src/MyApplication/libs/BmobSDKDemo_v3.6.0/BmobDemo/app/src/main/java/cn/bmob/sdkdemo/push/ActBmobPush.java
index f2ba0f8..4577db6 100644
--- a/src/MyApplication/libs/BmobSDKDemo_v3.6.0/BmobDemo/app/src/main/java/cn/bmob/sdkdemo/push/ActBmobPush.java
+++ b/src/MyApplication/libs/BmobSDKDemo_v3.6.0/BmobDemo/app/src/main/java/cn/bmob/sdkdemo/push/ActBmobPush.java
@@ -1,4 +1,3 @@
-
package cn.bmob.sdkdemo.push;
import android.os.Bundle;
diff --git a/src/MyApplication/settings.gradle b/src/MyApplication/settings.gradle
index e7b4def..f7e3ac0 100644
--- a/src/MyApplication/settings.gradle
+++ b/src/MyApplication/settings.gradle
@@ -1 +1,2 @@
-include ':app'
+include ':app', ':my_library'
+project(':my_library').projectDir = new File('library')
\ No newline at end of file