项目中遇到了需要在webview上传图片的需求,搜索了一把,找到几个可行的方法,同时也踩了个webview的坑,总结一下

我找到的是这样的方法

***首先 重写WebChromeClient 添加openFileChooser 方法

   // For Android 3.0+
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {//最终调用的都是这个
if (mUploadMessage != null) return;//坑就在这里 看后边注释
mUploadMessage = uploadMsg;
selectImage();
}

// For Android < 3.0
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
openFileChooser(uploadMsg, "");
}

// For Android > 4.1.1
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
openFileChooser(uploadMsg, acceptType);
}



*** 然后自己实现selectImage()方法

```
private void selectImage() {//模仿IOS的弹出框
List<map <String, String>> list = new ArrayList<>();
HashMap<string , String> ch1 = new HashMap<>();
HashMap</string><string , String> ch2 = new HashMap<>();
HashMap</string><string , String> ch3 = new HashMap<>();
ch1.put("key", "从相册选择");
ch2.put("key", "拍照上传");
ch3.put("key", "取消");

<pre><code> list.add(ch1);
list.add(ch2);
list.add(ch3);
ListAdapter ad = new SimpleAdapter(this, list, R.layout.my_simple_list_item_1, new String[]{"key"}, new int[]{android.R.id.text1});
chosePicDialog = new AlertDialog.Builder(this).setAdapter(ad, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
switch (i) {
case 0:
getImageFromAlbum();

break;
case 1:
getImageFromCamera();

break;
case 2:
mUploadMessage.onReceiveValue(null);//这里是坑,如果取消了 不调用这句mUploadMessage.onReceiveValue()的话 整个webview就都没有响应了
mUploadMessage = null;//还有这里 上边已标出
break;
}

}
}).setCancelable(false).create();
chosePicDialog.getWindow().setGravity(Gravity.BOTTOM);
chosePicDialog.show();
}
</code></pre>

```

然后分别实现 从图库选择和拍照上传的方法

```
/**
* 调用相册
<em>/
protected void getImageFromAlbum() {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/</em>");//相片类型
startActivityForResult(intent, REQUEST_CODE_PICK_IMAGE);
}

<pre><code>/**
* 调用相机
*/
protected void getImageFromCamera() {//这里采用的是获取拍照原图的方法
String state = Environment.getExternalStorageState();
if (state.equals(Environment.MEDIA_MOUNTED)) {
File f = FileUtil.getNewPicFilePath();
Uri u = Uri.fromFile(f);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, u);
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
startActivityForResult(intent,REQUEST_CODE_CAPTURE_CAMEIA);
} else {
Toast.makeText(getApplicationContext(), "请确认已经插入SD卡", Toast.LENGTH_LONG).show();
}
}
</code></pre>

```
***FileUtil.class内容

```
public class FileUtil {
private static String LastPicFilePath = null;

<pre><code>public static File getNewPicFilePath() {
String dirStr = Environment.getExternalStorageDirectory().getPath() + "/DCIM/Camera/";

File dir = new File(dirStr);
if (!dir.exists()) {
dir.mkdirs();
}
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
String nowTime = format.format(new Date());
String localTempFileName = nowTime + ".jpg";
File f = new File(dir, localTempFileName);
setLastPicFilePath(f.getPath());
Log.e("getLastPicFilePath",getLastPicFilePath());
return f;
}

public static String getLastPicFilePath() {
return LastPicFilePath;
}

public static void setLastPicFilePath(String lastPicFilePath) {
LastPicFilePath = lastPicFilePath;
}
</code></pre>

}
```
***再重写onActivityResult

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != RESULT_OK) {
mUploadMessage.onReceiveValue(null);//这里防止拍照的时候取消了回来webview无响应的问题,这里是大坑
mUploadMessage = null;//上边注释说了,这里是坑
mWebView.requestFocus();
return;
}
if (requestCode == REQUEST_CODE_PICK_IMAGE) {
Uri uri = data.getData();
//to do find the path of pic by uri
mUploadMessage.onReceiveValue(uri);
} else if (requestCode == REQUEST_CODE_CAPTURE_CAMEIA) {
Uri uri = Uri.parse(FileUtil.getLastPicFilePath());//从上边指定的地址生成uri
mUploadMessage.onReceiveValue(uri);
}
super.onActivityResult(requestCode, resultCode, data);
}


总结



总体来说最坑的就是这个 mUploadMessage.onReceiveValue( );方法
没看WebChromeClient源码 猜想是如果不回调这句的话webview会一直等着你操作,造成整个webview界面没有响应,这个问题让我纠结了一下午时间,总结出来,希望对其他人有帮助。

ps:今天看到wordpress有更新了,果断更新,但是不知道怎么回事,结果一直停留在“正在执行例行维护,请一分钟后回来”的状态了,这个问题一定有解决方法,所以搜索到了这篇文章,已测,可行。感谢原作者



WordPress在升级程序、主题、插件时,都会先切换到维护模式,也就是显示 “正在执行例行维护,请一分钟后回来(Briefly unavailable for scheduled maintenance. Check back in a minute)”,如果升级顺利,也就几秒左右就恢复正常;但是如果由于网速不佳等原因导致升级中断,WordPress就会一直停留在维护模式,不论前台还是后台,都一直显示“正在执行例行维护,请一分钟后回来“。

如何解决这个问题呢?

1.马上通过FTP登录你的网站,删除WordPress根目录下的 .maintenance ,刷新网页即可。

2.但是有时候你会发现,根目录根本就没有 .maintenance!倡萌最近就遇到这个问题,最初以为是隐藏了,所以使用SSH登录服务器,但是依旧没有看到,怎么办?其实有一个比较简单的办法,直接新建一个空的txt文本,上传到主机空间中,然后重命名为 .maintenance,然后你会发现 .maintenance 居然不见了!不用担心,重新刷新你的网站,是不是正常了?!

3.如果还是不行,或者你想让它以后可以显示 .maintenance ,那就打开 /wp-admin/includes/class-wp-filesystem-direct.php

找到下面的代码:


function mkdir($path, $chmod = false, $chown = false, $chgrp = false) {
// safe mode fails with a trailing slash under certain PHP versions.
$path = untrailingslashit($path);
if ( empty($path) )
return false;

if ( ! $chmod )
$chmod = FS_CHMOD_DIR;

if ( ! @mkdir($path) )
return false;
$this->chmod($path, $chmod);
if ( $chown )
$this->chown($path, $chown);
if ( $chgrp )
$this->chgrp($path, $chgrp);
return true;
}



将其改为:


function mkdir($path, $chmod = false, $chown = false, $chgrp = false) {
// safe mode fails with a trailing slash under certain PHP versions.
if ( ! $chmod )
$chmod = $this->permission;

if(ini_get('safe_mode') && substr($path, -1) == '/')
{
$path = substr($path, 0, -1);
}

if ( ! @mkdir($path) )
return false;
$this->chmod($path, $chmod);
if ( $chown )
$this->chown($path, $chown);
if ( $chgrp )
$this->chgrp($path, $chgrp);
return true;
}



然后刷新FTP目录,是不是看到.maintenance了,删除它吧!

原文链接:http://www.wpdaxue.com/briefly-unavailable-for-scheduled-maintenance.html

转载的,主要是以前看到过,但是一直没实行,今天按照文中做了一遍,第一次失败,又改了下参数,启动成功
原文地址:http://www.68idc.cn/help/opersys/ubuntu/20141111128088.html
‘’‘
1,如果装了sendmail的话,先卸载了。

yum remove sendmail
2,安装 Postfix

yum install postfix
3,更改默认MTA为Postfix:

/usr/sbin/alternatives --set mta /usr/sbin/sendmail.postfix
4,完事儿,再次检查下是否将MTA改为Postfix了:

alternatives --display mta
5,配置Postfix,vi编辑main.cf

vi /etc/postfix/main.cf
打开后分别找到以下几项,,将其前面的#去掉,并做配置:

myhostname = mail.imcn.me
mydomain = imcn.me
myorigin = $mydomain
inet_interfaces = all mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
mynetworks = 168.100.189.0/28, 127.0.0.0/8
relay_domains = (这里我留空启动不了,所以就使用了默认的 relay_domains = $mydestination)
home_mailbox = Maildir/
以上几个设置项不在同一个位置,需要分别寻找,并进行更改,其中相应的域名请改为自己的地址,mynetworks我是没有做改变,自动就有的。

配置文件解释:

mydomain:

mydomain参数是指email服务器的域名,请确保为正式域名(如centos.bz)

myhostname:

myhostname参数是指系统的主机名称(如我的服务器主机名称是mail.centos.bz)

myorigin:

myorigin参数指定本地发送邮件中来源和传递显示的域名。在我们的例子中,mydomain是centos.bz,也是我的域名。

对于下面的一行,我们的邮件地址是user@centos.bz而不是user@mail.centos.bz。

myorigin = $mydomain

mynetworks:

mynetworks参数指定受信任SMTP的列表,具体的说,受信任的SMTP客户端允许通过Postfix传递邮件。

mydestination:

mydestination参数指定哪些邮件地址允许在本地发送邮件。这是一组被信任的允许通过服务器发送或传递邮件的IP地址。用户试图通过发送从此处未列出的IP地址的原始服务器的邮件将被拒绝。

inet_interfaces:

inet_interfaces参数设置网络接口以便Postfix能接收到邮件。

relay_domains:

该参数是系统传递邮件的目的域名列表。如果留空,我们保证了我们的邮件服务器不对不信任的网络开放。

home_mailbox:

该参数设置邮箱路径与用户目录有关,也可以指定要使用的邮箱风格。

6,检测并启动Postfix

service postfix status //检测,若已启动会列出其PID,如下: master (pid 25579) is running... //若未启动,执行以下命令: service postfix start
7,设置开机启动

chkconfig postfix on
我自己的安装到此为止就结束了,因为我只需要的是mail功能,并非搭建邮件服务器。此时测试邮件发送,OK。

参考资料:

补充:如果你之前没有配置过 sendmail 组件,那你很可能没有修改 php.ini 的邮件发送路径,那样可能无法发送邮件。

所以你需要配置php.ini,填写sendmail的绝对路径:

使用命令打开编辑php.ini

vi /usr/local/php/etc/php.ini
输入?sendmail_path 查找定位(或者手动跳转找到sendmail_path),你会发现默认是下面的代码

;sendmail_path =
按 i 进入编辑,将这行修改为

sendmail_path = /usr/sbin/sendmail -t -i
按 Esc 键退出编辑,输入 :wq 保存退出

5.重启php-fpm进程

/etc/init.d/php-fpm restart
’‘’

原文:http://my.oschina.net/djone/blog/408110
使用SwipeRefreshLayout,网上资料copy了一个OnScrollListener给ListView,

结果当第一个item长度超过一屏,明明还没有到达列表顶部,Scroll事件就被拦截,列表无法滚动,同时启动了刷新。
修正代码后,自定义的OnScrollListener如下:

/** 由于Listview与下拉刷新的Scroll事件冲突, 使用这个ScrollListener可以避免Listview滑动异常 */
public static class SwpipeListViewOnScrollListener implements AbsListView.OnScrollListener {

private SwipeRefreshLayout mSwipeView;
private AbsListView.OnScrollListener mOnScrollListener;

public SwpipeListViewOnScrollListener(SwipeRefreshLayout swipeView) {
mSwipeView = swipeView;
}

public SwpipeListViewOnScrollListener(SwipeRefreshLayout swipeView,
OnScrollListener onScrollListener) {
mSwipeView = swipeView;
mOnScrollListener = onScrollListener;
}

@Override
public void onScrollStateChanged(AbsListView absListView, int i) {
}

@Override
public void onScroll(AbsListView absListView, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
View firstView = absListView.getChildAt(firstVisibleItem);

// 当firstVisibleItem是第0位。如果firstView==null说明列表为空,需要刷新;或者top==0说明已经到达列表顶部, 也需要刷新
if (firstVisibleItem == 0 && (firstView == null || firstView.getTop() == 0)) {
mSwipeView.setEnabled(true);
} else {
mSwipeView.setEnabled(false);
}
if (null != mOnScrollListener) {
mOnScrollListener.onScroll(absListView, firstVisibleItem,
visibleItemCount, totalItemCount);
}
}
}

关键代码以下:

  @Override  
public void onReceivedError(WebView view, int errorCode,  
  String description, String failingUrl) {  
    //用javascript隐藏系统定义的404页面信息  
  String data = "Page NO FOUND!";  
view.loadUrl("javascript:document.body.innerHTML=\\""+data+"\\"");  
}




出处:http://blog.csdn.net/feifei454498130/article/details/23627557

主要是在WebViewClient里,重载OnReceivedError的方法,然后通过javascript操作dom去改变内容。

而网上大多数的处理方式是view.loadUrl(指向一个assets目录下的html文件或者"about:blank"),这样处理的话,在重新刷新时就会刷新当前这个错误的页面,或者在处理goBack()时候会出现一些问题。而通过以上方式则可以避免相应的问题。