package com.rdgk.cemetery.weiview; import android.Manifest; import android.annotation.TargetApi; import android.app.Activity; import android.content.ClipData; import android.content.ContentValues; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.Bitmap; import android.icu.text.SimpleDateFormat; import android.media.MediaPlayer; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.util.Base64; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.webkit.ValueCallback; import android.webkit.WebSettings; import android.webkit.WebView; import android.widget.LinearLayout; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.core.content.FileProvider; import androidx.core.os.EnvironmentCompat; import com.just.agentweb.AgentWeb; import com.just.agentweb.PermissionInterceptor; import com.just.agentweb.WebChromeClient; import com.just.agentweb.WebViewClient; //import com.king.zxing.CameraScan; import com.rdgk.cemetery.activity.NfcActivity; import com.rdgk.cemetery.event.EventData; import com.rdgk.cemetery.R; import com.rdgk.cemetery.event.EventMp3; import com.tencent.trtc.videocall.TrtcEvent; import com.rdgk.cemetery.utils.ToastUtil; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import org.json.JSONException; import org.json.JSONObject; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.Date; import java.util.List; import java.util.Locale; /** * @Author pwxmax * @Date 2020.6.11 * @Discription 对接H5通用的 Activity */ public class WebViewActivity extends NfcActivity { private MediaPlayer mMediaPlayer = null;//媒体播放器 LinearLayout linearLayout; protected AgentWeb mAgentWeb; private String url; private int REQUEST_CODE = 200; // 拍照的requestCode private static final int CAMERA_REQUEST_CODE = 0x00000010; // 申请相机权限的requestCode private static final int PERMISSION_CAMERA_REQUEST_CODE = 0x00000012; /** * 用于保存拍照图片的uri */ private Uri mCameraUri; /** * 用于保存图片的文件路径,Android 10以下使用图片路径访问图片 */ private String mCameraImagePath; /** * 是否是Android 10以上手机 */ private boolean isAndroidQ = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q; private ValueCallback uploadMessage; private ValueCallback uploadMessageAboveL; private final static int FILE_CHOOSER_RESULT_CODE = 10000; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_web); EventBus.getDefault().register(this); initView(); } @Override protected void onNfcTouch() { readNfc(); } public void playjieting() { mMediaPlayer = MediaPlayer.create(this, R.raw.jieting);//加载res/raw的happyis.mp3文件 mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mediaPlayer) { if (mMediaPlayer != null) { mMediaPlayer.start(); } } }); mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { @Override public boolean onError(MediaPlayer mediaPlayer, int i, int i1) { mediaPlayer.seekTo(0); return false; } }); mMediaPlayer.start(); } public void playhujiao() { mMediaPlayer = MediaPlayer.create(this, R.raw.hujiao);//加载res/raw的happyis.mp3文件 mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mediaPlayer) { if (mMediaPlayer != null) { mMediaPlayer.start(); } } }); mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { @Override public boolean onError(MediaPlayer mediaPlayer, int i, int i1) { mediaPlayer.seekTo(0); return false; } }); mMediaPlayer.start(); } public void playguaduan() { //加载res/raw的happyis.mp3文件 mMediaPlayer = MediaPlayer.create(this, com.tencent.trtc.videocall.R.raw.guaduan); mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { if (mMediaPlayer != null) { } } }); mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { @Override public boolean onError(MediaPlayer mediaPlayer, int i, int i1) { mediaPlayer.seekTo(0); return false; } }); mMediaPlayer.start(); } public void stophujiao() { if (mMediaPlayer != null) { mMediaPlayer.stop(); mMediaPlayer = null; } } public void readNfc() { String s = null; try { //read nfc content from tag; s = this.readNfcContent(); s = s.substring(4); mAgentWeb.getJsAccessEntrace().quickCallJs("FsNfc", s); ToastUtil.showToast(s); } catch (Exception e) { Log.e("pwx", e.toString() ); ToastUtil.showToast("NFC读取失败"); } } public void writeNfcContent() { SimpleDateFormat dateFormat = null; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); } String content = dateFormat.format(System.currentTimeMillis()); try { //write something to tag; this.writeNfc(content); } catch (Exception e) { ToastUtil.showToast("NFC读取失败"); } } public void clearNfc() { try { //clear nfcContent this.deleteNfc(); } catch (Exception e) { ToastUtil.showToast("NFC读取失败"); } } private void initView() { url = getIntent().getStringExtra("url"); // url="http://192.168.1.11:8080"; linearLayout = findViewById(R.id.ll_webview); AndroidWebView.assistActivity(this); mAgentWeb = AgentWeb.with(this) .setAgentWebParent(linearLayout, new LinearLayout.LayoutParams(-1, -1)) .closeIndicator() .setWebChromeClient(mWebChromeClient) .setWebViewClient(mWebViewClient) // .setPermissionInterceptor(mPermissionInterceptor) .createAgentWeb() .go(url); if (mAgentWeb != null) { mAgentWeb.getJsInterfaceHolder().addJavaObject("android", new AndroidInterface(mAgentWeb, this)); //注入对象 WebSettings webSettings = mAgentWeb.getAgentWebSettings().getWebSettings(); webSettings.setUseWideViewPort(true);//关键点 webSettings.setDomStorageEnabled(true); webSettings.setDefaultTextEncodingName("UTF-8"); webSettings.setAllowContentAccess(true); // 是否可访问Content Provider的资源,默认值 true webSettings.setLoadWithOverviewMode(true); webSettings.setCacheMode(WebSettings.LOAD_DEFAULT); webSettings.setBuiltInZoomControls(false); // 设置显示缩放按钮 // webSettings.setAppCacheEnabled(true);//是否使用缓存 webSettings.setSupportZoom(false); // 支持缩放 webSettings.setAllowFileAccess(true); //允许加载本地文件html file协议, 这可能会造成不安全 , 建议重写关闭 webSettings.setAllowFileAccessFromFileURLs(true); //通过 file url 加载的 Javascript 读取其他的本地文件 .建议关闭 webSettings.setAllowUniversalAccessFromFileURLs(true);//允许通过 file url 加载的 Javascript 可以访问其他的源,包括其他的文件和 http,https 等其他的源 mAgentWeb.getWebCreator().getWebView().setOverScrollMode(WebView.OVER_SCROLL_NEVER); } } protected PermissionInterceptor mPermissionInterceptor = new PermissionInterceptor() { /** * PermissionInterceptor 能达到 url1 允许授权, url2 拒绝授权的效果。 * @param url * @param permissions * @param action * @return true 该Url对应页面请求权限进行拦截 ,false 表示不拦截。 */ @Override public boolean intercept(String url, String[] permissions, String action) { //Log.i(TAG, "mUrl:" + url + " permission:" + mGson.toJson(permissions) + " action:" + action); return false; } }; private WebViewClient mWebViewClient = new WebViewClient() { @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { //do you work } }; private WebChromeClient mWebChromeClient = new WebChromeClient() { @Override public void onProgressChanged(WebView view, int newProgress) { //do you work } // For Android < 3.0 public void openFileChooser(ValueCallback valueCallback) { uploadMessage = valueCallback; openImageChooserActivity(); } // For Android >= 3.0 public void openFileChooser(ValueCallback valueCallback, String acceptType) { uploadMessage = valueCallback; openImageChooserActivity(); } //For Android >= 4.1 public void openFileChooser(ValueCallback valueCallback, String acceptType, String capture) { uploadMessage = valueCallback; openImageChooserActivity(); } // For Android >= 5.0 @Override public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) { uploadMessageAboveL = filePathCallback; openImageChooserActivity(); return true; } }; // 2.回调方法触发本地选择文件 private void openImageChooserActivity() { // checkPermissionAndCamera(); Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("image/*");//图片上传 // i.setType("file/*");//文件上传 // i.setType("*/*");//文件上传 startActivityForResult(Intent.createChooser(i, "File Chooser"), FILE_CHOOSER_RESULT_CODE); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (mAgentWeb.handleKeyEvent(keyCode, event)) { return true; } if (keyCode == KeyEvent.KEYCODE_BACK) { } return super.onKeyDown(keyCode, event); } @Override protected void onPause() { // mAgentWeb.getWebLifeCycle().onPause(); super.onPause(); } // @Override // protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { // super.onActivityResult(requestCode, resultCode, data); // /** // * 处理二维码扫描结果 // */ // if (resultCode == RESULT_OK) { // switch (requestCode) { // case 200: // Bundle bundle = data.getExtras(); // String scanResult = bundle.getString(Constant.INTENT_EXTRA_KEY_QR_SCAN); //// String result = CameraScan.parseScanResult(data); // mAgentWeb.getJsAccessEntrace().quickCallJs("QRCode", scanResult); // break; // case CAMERA_REQUEST_CODE: // if (uploadMessageAboveL != null) { // Uri[] results = new Uri[]{mCameraUri}; // uploadMessageAboveL.onReceiveValue(results); // uploadMessageAboveL = null; //// onActivityResultAboveL(requestCode, resultCode, data); // } else if (uploadMessage != null) { // uploadMessage.onReceiveValue(mCameraUri); // uploadMessage = null; // } //// String uploadpath = Uri2PathUtil.getRealPathFromUri(this, mCameraUri); //// mAgentWeb.getJsAccessEntrace().quickCallJs("Camera", uploadpath); // break; // } // } else { // //这里uploadMessage跟uploadMessageAboveL在不同系统版本下分别持有了 // //WebView对象,在用户取消文件选择器的情况下,需给onReceiveValue传null返回值 // //否则WebView在未收到返回值的情况下,无法进行任何操作,文件选择器会失效 // if (uploadMessage != null) { // uploadMessage.onReceiveValue(null); // uploadMessage = null; // } else if (uploadMessageAboveL != null) { // uploadMessageAboveL.onReceiveValue(null); // uploadMessageAboveL = null; // } // } // } // // // 3.选择图片后处理 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == FILE_CHOOSER_RESULT_CODE) { if (null == uploadMessage && null == uploadMessageAboveL) return; Uri result = data == null || resultCode != RESULT_OK ? null : data.getData(); // Uri result = (((data == null) || (resultCode != RESULT_OK)) ? null : data.getData()); if (uploadMessageAboveL != null) { onActivityResultAboveL(requestCode, resultCode, data); } else if (uploadMessage != null) { uploadMessage.onReceiveValue(result); uploadMessage = null; } } else { //这里uploadMessage跟uploadMessageAboveL在不同系统版本下分别持有了 //WebView对象,在用户取消文件选择器的情况下,需给onReceiveValue传null返回值 //否则WebView在未收到返回值的情况下,无法进行任何操作,文件选择器会失效 if (uploadMessage != null) { uploadMessage.onReceiveValue(null); uploadMessage = null; } else if (uploadMessageAboveL != null) { uploadMessageAboveL.onReceiveValue(null); uploadMessageAboveL = null; } } } // 4. 选择内容回调到Html页面 @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void onActivityResultAboveL(int requestCode, int resultCode, Intent intent) { if (requestCode != FILE_CHOOSER_RESULT_CODE || uploadMessageAboveL == null) return; Uri[] results = null; if (resultCode == Activity.RESULT_OK) { if (intent != null) { String dataString = intent.getDataString(); ClipData clipData = intent.getClipData(); if (clipData != null) { results = new Uri[clipData.getItemCount()]; for (int i = 0; i < clipData.getItemCount(); i++) { ClipData.Item item = clipData.getItemAt(i); results[i] = item.getUri(); } } if (dataString != null) results = new Uri[]{Uri.parse(dataString)}; } } uploadMessageAboveL.onReceiveValue(results); uploadMessageAboveL = null; } @Subscribe(threadMode = ThreadMode.MAIN) public void evemp3(EventMp3 eventData) { if (eventData.getCode() == 1) { playhujiao(); } else if (eventData.getCode() == 2) { playjieting(); } else if (eventData.getCode() == 3) { stophujiao(); } else if (eventData.getCode() == 4) { playguaduan(); } } @Subscribe(threadMode = ThreadMode.MAIN) public void stopServiceEvent(EventData eventData) { if (eventData.getCode() == 1) { mAgentWeb.getJsAccessEntrace().quickCallJs("StartService", "1"); } else if (eventData.getCode() == 2) { mAgentWeb.getJsAccessEntrace().quickCallJs("StartService", "2"); } else if (eventData.getCode() == 3) { checkPermissionAndCamera(); } } @Subscribe(threadMode = ThreadMode.MAIN) public void stopTrtcEvent(TrtcEvent trtcEvent) { if (trtcEvent.getCode() == 2) { JSONObject j = new JSONObject(); try { j.put("type", trtcEvent.getTrtcType()); mAgentWeb.getJsAccessEntrace().quickCallJs("TRtc", j.toString()); } catch (JSONException e) { } } } /** * 检查权限并拍照。 * 调用相机前先检查权限。 */ private void checkPermissionAndCamera() { int hasCameraPermission = ContextCompat.checkSelfPermission(getApplication(), Manifest.permission.CAMERA); if (hasCameraPermission == PackageManager.PERMISSION_GRANTED) { //有权限,调起相机拍照。 openCamera(); } else { //没有权限,申请权限。 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, PERMISSION_CAMERA_REQUEST_CODE); ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_CAMERA_REQUEST_CODE); } } /** * 处理权限申请的回调。 * * @param requestCode * @param permissions * @param grantResults */ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == PERMISSION_CAMERA_REQUEST_CODE) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { //允许权限,有调起相机拍照。 openCamera(); } else { //拒绝权限,弹出提示框。 Toast.makeText(this, "拍照权限被拒绝", Toast.LENGTH_LONG).show(); } } } /** * 调起相机拍照 */ private void openCamera() { Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // 判断是否有相机 if (captureIntent.resolveActivity(getPackageManager()) != null) { File photoFile = null; Uri photoUri = null; if (isAndroidQ) { // 适配android 10 photoUri = createImageUri(); } else { try { photoFile = createImageFile(); } catch (IOException e) { e.printStackTrace(); } if (photoFile != null) { mCameraImagePath = photoFile.getAbsolutePath(); System.out.println("path = " + mCameraImagePath); photoUri = FileProvider.getUriForFile(WebViewActivity.this, "com.rdgk.cemetery.fileprovider", photoFile); } } System.out.println("photoUri = " + photoUri); mCameraUri = photoUri; if (photoUri != null) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { List resInfoList = getPackageManager() .queryIntentActivities(captureIntent, PackageManager.MATCH_DEFAULT_ONLY); for (ResolveInfo resolveInfo : resInfoList) { String packageName = resolveInfo.activityInfo.packageName; grantUriPermission(packageName, photoUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION); } } captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); captureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); startActivityForResult(captureIntent, CAMERA_REQUEST_CODE); } } } /** * 创建图片地址uri,用于保存拍照后的照片 Android 10以后使用这种方法 * * @return 图片的uri */ private Uri createImageUri() { //设置保存参数到ContentValues中 ContentValues contentValues = new ContentValues(); //设置文件名 contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, System.currentTimeMillis() + ""); //兼容Android Q和以下版本 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { //android Q中不再使用DATA字段,而用RELATIVE_PATH代替 //TODO RELATIVE_PATH是相对路径不是绝对路径;照片存储的地方为:内部存储/Pictures/preventpro contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/preventpro"); } //设置文件类型 contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/JPEG"); //执行insert操作,向系统文件夹中添加文件 //EXTERNAL_CONTENT_URI代表外部存储器,该值不变 Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues); return uri; } /** * 创建保存图片的文件 * * @return * @throws IOException */ private File createImageFile() throws IOException { String imageName = null; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { imageName = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()) + ".jpg"; } // File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); // File storageDir = Environment.getExternalStoragePublicDirectory( // Environment.DIRECTORY_PICTURES); File storageDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "Pictures" + File.separator + "abc"); if (!storageDir.exists()) storageDir.mkdirs(); File tempFile = new File(storageDir, imageName); if (!Environment.MEDIA_MOUNTED.equals(EnvironmentCompat.getStorageState(tempFile))) { return null; } return tempFile; } /** * 文件转base64字符串 * * @param file * @return */ public String fileToBase64(File file) { String base64 = null; InputStream in = null; try { in = new FileInputStream(file); byte[] bytes = new byte[in.available()]; int length = in.read(bytes); base64 = Base64.encodeToString(bytes, 0, length, Base64.DEFAULT); } catch (FileNotFoundException e) { // TODO Auto-generated catch block ToastUtil.showToast("文件读取异常"); } catch (IOException e) { // TODO Auto-generated catch block ToastUtil.showToast("IO读取异常"); } finally { try { if (in != null) { in.close(); } } catch (IOException e) { // TODO Auto-generated catch block ToastUtil.showToast("IO关闭异常"); } } return base64; } @Override protected void onResume() { // mAgentWeb.getWebLifeCycle().onResume(); super.onResume(); } @Override public void onDestroy() { super.onDestroy(); mAgentWeb.getWebLifeCycle().onDestroy(); EventBus.getDefault().unregister(this); } @Override public void onPointerCaptureChanged(boolean hasCapture) { } }