接入智齿客服网页端流程:
主要问题就是Android webview 屏蔽了上传文件功能,本文附带解决了WebView 不支持<input type=file>文件上传,WebView 点击没有反应的问题;
智齿客服网页端接入有两种部署方式。1、网页组件;2、聊天链接。本文档不涉及业务流程,只讲述开发接入过程;
今天主要说一下Android 、ios 对 聊天链接 这种方式的接入,第一种接入方式后期再做描述。
1、 先注册智齿客服,然后用超级管理员账号登陆后到“设置-支持渠道”获取部署代码;
例:获取聊天链接如下:
https://www.sobot.com/chat/pc/index.html?sysNum=a047ca3c8fec47cca963d4a6e27b8706
2、这是智齿客服官方提供的链接开发文档:智齿客服官方文档,文档最后列出了聊天链接可以拼接的参数,可根据需要自行配置,值得注意的是customerFields 字段,是智齿客服提供的允许自定义的字段,登入智齿客服官网 到“设置-自定义字段” 中设置你所需要的字段。
例如新建字段名称为“游戏”,点击“显示ID”,查看自定义字段所对应的参数。最后将自定义字段拼接成json字符串,拼接到链接后面。如下:
拼接链接如下:https://www.sobot.com/chat/pc/index.html?sysNum=a047ca3c8fec47cca963d4a6e27b8706&customerFileds={"customField1":"麻将","customField2":"北京"}
3、通过Android或IOS , webview 加载此链接。说明:ios 不需要做任何更改,直接加载链接就可以使用智齿客服网页版的聊天链接了。Android直接加载无法上传图片和拍照。
4、Android 上传图片和拍照问题解决;
由于安全因素android webview屏蔽了文件上传控件,但是他并没有完全封掉。
解决方法步骤如下:
(1)、Activity 定义:
private static final int REQUEST_CODE_PERMISSION_CAMERA = 0x03;
private static final int REQUEST_CODE_CAMERA = 0x02;
private static final int REQUEST_CODE_ALBUM = 0x01;
private ValueCallback<Uri[]> uploadMessageAboveL;
private ValueCallback<Uri> uploadMessage;
(2)、 扩展WebChromeClient
webView.setWebChromeClient(mWebChromeClient);
protected WebChromeClient mWebChromeClient = new WebChromeClient() {
@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
if (basetitle != null && !TextUtils.isEmpty(title)) {
basetitle.setText(title);
} else {
basetitle.setText(" ");
}
}
// For Android 4.1 - 5.0
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> valueCallback, FileChooserParams fileChooserParams) {
uploadMessageAboveL = valueCallback;
uploadPicture();
return true;
}
// For Android >= 5.1
@Override
public void openFileChooser(ValueCallback<Uri> valueCallback, String s, String s1) {
//super.openFileChooser(valueCallback, s, s1);
uploadMessage = valueCallback;
uploadPicture();
}
};
(3)、解决选择文件后按钮失效问题,需要覆写onActivityResult方法
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_ALBUM || requestCode == REQUEST_CODE_CAMERA) {
if (uploadMessage == null && uploadMessageAboveL == null) {
return;
}
//取消拍照或者取消选择相册
if (resultCode != RESULT_OK) {
if (uploadMessage != null) {
uploadMessage.onReceiveValue(null);
uploadMessage = null;
}
if (uploadMessageAboveL != null) {
uploadMessageAboveL.onReceiveValue(null);
uploadMessageAboveL = null;
}
}
//拍照成功或选择照片
if (resultCode == RESULT_OK) {
Uri imageUri = null;
switch (requestCode) {
case REQUEST_CODE_ALBUM:
if (data != null) {
imageUri = data.getData();
}
break;
case REQUEST_CODE_CAMERA:
if (!TextUtils.isEmpty(mCurrentPhotoPath)) {
File file = new File(mCurrentPhotoPath);
Uri loadUri = Uri.fromFile(file);
Intent localIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, loadUri);
sendBroadcast(localIntent);
imageUri = Uri.fromFile(file);
mLastPhotoPath = mCurrentPhotoPath;
}
break;
}
//上传文件
if (uploadMessage != null) {
uploadMessage.onReceiveValue(imageUri);
uploadMessage = null;
}
if (uploadMessageAboveL != null) {
uploadMessageAboveL.onReceiveValue(new Uri[]{imageUri});
uploadMessageAboveL = null;
}
}
}
}
(4)、以上是主要功能点,下面是我自己用到的一个完整文件,可以参考,里面内容部分多余的请自动忽略。
public class BannerWebActivity extends BaseActivity implements View.OnClickListener {
private static final int REQUEST_CODE_PERMISSION_CAMERA = 0x03;
private static final int REQUEST_CODE_CAMERA = 0x02;
private static final int REQUEST_CODE_ALBUM = 0x01;
private int type;
private WebView webView;
private ProgressBar pbProcess;
private String weburl;
private ImageView basetitleleftim;
private TextView basetitle;
private ValueCallback<Uri[]> uploadMessageAboveL;
private ValueCallback<Uri> uploadMessage;
private String mLastPhotoPath;
private Thread mThread;
Context mContext;
private String mCurrentPhotoPath;
@Override
public void initView() {
mContext = getApplicationContext();
basetitleleftim = getViewID(R.id.basetitle_leftim);
webView = getViewID(R.id.webview);
pbProcess = getViewID(R.id.pb_process);
basetitle = getViewID(R.id.basetitle_title);
Intent intent = getIntent();
weburl = intent.getStringExtra("weburl");
type = intent.getIntExtra("type", 0);
basetitleleftim.setOnClickListener(this);
if (type == 1000) {
OkHttpUtils.getInstance().getToken(this, AgencyUrl.ReadStrategyUrl, 1, BaseDiabean.class);
}
}
@Override
public void initData() throws Exception {
WebSettings settings = webView.getSettings();
/* 大部分网页需要自己保存一些数据,这个时候就的设置下面这个属性 */
settings.setDomStorageEnabled(true);
settings.setDatabaseEnabled(true);
/* 设置缓存模式,我这里使用的默认,不做多讲解 */
settings.setCacheMode(WebSettings.LOAD_DEFAULT);
/* 设置支持Js,必须设置的,不然网页基本上不能看 */
settings.setJavaScriptEnabled(true);
settings.setAppCacheEnabled(true);
settings.setAppCachePath(context.getCacheDir().getAbsolutePath());
/* 设置为使用webview推荐的窗口 */
settings.setUseWideViewPort(true);
settings.setLoadWithOverviewMode(true);
/* 设置是否允许webview使用缩放的功能,我这里设为false,不允许 */
settings.setBuiltInZoomControls(false);
/* webview 不显示图片兼容 */
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
settings.setMixedContentMode(android.webkit.WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
webView.setWebChromeClient(mWebChromeClient);
webView.setWebViewClient(mWebViewClient);
webView.setDownloadListener(new DownloadListener() {
@Override
public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.setData(Uri.parse(url));
startActivity(intent);
}
});
webView.setHorizontalScrollBarEnabled(false);
webView.loadUrl(weburl);
}
protected WebViewClient mWebViewClient = new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) { // 重写此方法表明点击网页里面的链接不调用系统浏览器,而是在本WebView中显示
view.loadUrl(url);//加载需要显示的网页
return true;
// return super.shouldOverrideUrlLoading(view, url);
}
};
protected WebChromeClient mWebChromeClient = new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int newProgress) {
// super.onProgressChanged(view, newProgress);
pbProcess.setProgress(newProgress);
if (newProgress >= 100) {
pbProcess.setVisibility(View.GONE);
} else {
pbProcess.setVisibility(View.VISIBLE);
}
}
@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
if (basetitle != null && !TextUtils.isEmpty(title)) {
basetitle.setText(title);
} else {
basetitle.setText(" ");
}
}
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> valueCallback, FileChooserParams fileChooserParams) {
uploadMessageAboveL = valueCallback;
uploadPicture();
return true;
}
@Override
public void openFileChooser(ValueCallback<Uri> valueCallback, String s, String s1) {
uploadMessage = valueCallback;
uploadPicture();
}
};
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
takePhoto();
}
};
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults == null && grantResults.length == 0) {
return;
}
if (requestCode == REQUEST_CODE_PERMISSION_CAMERA) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
takePhoto();
} else {
new AlertDialog.Builder(mContext)
.setTitle("无法拍照")
.setMessage("您未授予拍照权限")
.setNegativeButton("取消", null)
.setPositiveButton("去设置", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent localIntent = new Intent();
localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
localIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
localIntent.setData(Uri.fromParts("package", getPackageName(), null));
startActivity(localIntent);
}
}).create().show();
}
}
}
/**
* 选择相机或者相册
*/
public void uploadPicture() {
AlertDialog.Builder builder = new AlertDialog.Builder(BannerWebActivity.this);
builder.setTitle("请选择图片上传方式");
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
if (uploadMessage != null) {
uploadMessage.onReceiveValue(null);
uploadMessage = null;
}
if (uploadMessageAboveL != null) {
uploadMessageAboveL.onReceiveValue(null);
uploadMessageAboveL = null;
}
}
});
//相机
builder.setPositiveButton("相机", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (!TextUtils.isEmpty(mLastPhotoPath)) {
mThread = new Thread(new Runnable() {
@Override
public void run() {
File file = new File(mLastPhotoPath);
if (file != null) {
file.delete();
}
mHandler.sendEmptyMessage(1);
}
});
mThread.start();
} else {
if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
takePhoto();
} else {
ActivityCompat.requestPermissions(BannerWebActivity.this, new String[]{Manifest.permission.CAMERA}, REQUEST_CODE_PERMISSION_CAMERA);
}
}
}
});
builder.setNegativeButton("相册", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
chooseAlbumPic();
}
});
builder.create().show();
}
/**
* 拍照
*/
private void takePhoto() {
StringBuilder fileName = new StringBuilder();
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
fileName.append(UUID.randomUUID()).append("_upload.png");
File tempFile = new File(mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES), fileName.toString());
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri uri = FileProvider.getUriForFile(mContext, BuildConfig.APPLICATION_ID + ".fileProvider", tempFile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
} else {
Uri uri = Uri.fromFile(tempFile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
}
mCurrentPhotoPath = tempFile.getAbsolutePath();
startActivityForResult(intent, REQUEST_CODE_CAMERA);
}
/**
* 选择相册照片
*/
private void chooseAlbumPic() {
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
startActivityForResult(Intent.createChooser(i, "Image Chooser"), REQUEST_CODE_ALBUM);
}
/*
* 回调
*
* */
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_ALBUM || requestCode == REQUEST_CODE_CAMERA) {
if (uploadMessage == null && uploadMessageAboveL == null) {
return;
}
//取消拍照或者取消选择相册
if (resultCode != RESULT_OK) {
if (uploadMessage != null) {
uploadMessage.onReceiveValue(null);
uploadMessage = null;
}
if (uploadMessageAboveL != null) {
uploadMessageAboveL.onReceiveValue(null);
uploadMessageAboveL = null;
}
}
//拍照成功或选择照片
if (resultCode == RESULT_OK) {
Uri imageUri = null;
switch (requestCode) {
case REQUEST_CODE_ALBUM:
if (data != null) {
imageUri = data.getData();
}
break;
case REQUEST_CODE_CAMERA:
if (!TextUtils.isEmpty(mCurrentPhotoPath)) {
File file = new File(mCurrentPhotoPath);
Uri loadUri = Uri.fromFile(file);
Intent localIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, loadUri);
sendBroadcast(localIntent);
imageUri = Uri.fromFile(file);
mLastPhotoPath = mCurrentPhotoPath;
}
break;
}
//上传文件
if (uploadMessage != null) {
uploadMessage.onReceiveValue(imageUri);
uploadMessage = null;
}
if (uploadMessageAboveL != null) {
uploadMessageAboveL.onReceiveValue(new Uri[]{imageUri});
uploadMessageAboveL = null;
}
}
}
}
@Override
public int setViewLayout() {
return R.layout.activity_banner_web;
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.basetitle_leftim:
if (webView != null && webView.canGoBack()) {
webView.goBack();
} else {
fishActivity(this);
}
break;
default:
break;
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (webView != null && webView.canGoBack()) {
webView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
public void onSuccessResponse(Call call, RBResponse resultBean, int requestCode) throws IOException {
if (requestCode == 1) {
BaseDiabean baseDiabean = (BaseDiabean) resultBean;
if (baseDiabean != null) {
if (baseDiabean.getCode() != 200) {
ToastUtils.showShort(this, baseDiabean.getMessage(), 1);
}
} else {
ToastUtils.showShort(this, "出错了", 1);
}
}
}
@Override
public void onFailResponse(Call call, IOException e, int requestCode) {
}
@Override
protected void onDestroy() {
if (webView != null) {
webView.setWebChromeClient(null);
webView.setWebViewClient(null);
webView.destroy();
webView = null;
}
super.onDestroy();
}
}
5、智齿客服聊天链接接入完毕。总结一下,主要要处理的一个问题就是Android webview 屏蔽了文件上传。解决了这个问题也就完全解决了,说明一下,选择拍照或者相册的弹窗,可以自己根据需要自己重新写一下UI样式。