Coin163

首页 > 翻看谷歌源码 那些让人感兴趣的东西--WebView如何申请授权

翻看谷歌源码 那些让人感兴趣的东西--WebView如何申请授权

相关标签: webview 谷歌 源码

2021腾讯云限时秒杀,爆款1核2G云服务器298元/3年!(领取2860元代金券),
地址https://cloud.tencent.com/act/cps/redirect?redirect=1062

2021阿里云最低价产品入口+领取代金券(老用户3折起),
入口地址https://www.aliyun.com/minisite/goods

转载请注明出处:王亟亟的大牛之路 强行安利下自己的收纳库(日更):https://github.com/ddwhan0123/Useful-Open-Source-Android 昨天写了个CardView的貌似,不太受欢迎,今天上午没啥大事就继续翻源码,这一篇讲的是WebView的授权实现(WebView这个坑大家怨声载道,现在看看官方是如何操作的吧) 先看下运行效果 OK,来看看包结构 比平时的那些sample东西稍微多点 其实主要业务就在 PermissionRequestFragment和ConfirmationDialogFragment里 我们一个个看(主要看授权行为) MainActivity初始化一些UI 然后把 Log部分和WebView部分以及bar逻辑的一些相关内容做了处理,不涉及授权操作(主要做呈现) 他继承于SampleActivityBase,也是做一些初始化Log的行为,这里不做解释 接下来是授权行为操作的PermissionRequestFragment(重要步骤已经注释) /** * This fragment shows a {@link WebView} and loads a web app from the {@link SimpleWebServer}. */public class PermissionRequestFragment extends Fragment implements ConfirmationDialogFragment.Listener {

private static final String TAG = PermissionRequestFragment.class.getSimpleName();

private static final String FRAGMENT_DIALOG = "dialog";

/** * We use this web server to serve HTML files in the assets folder. This is because we cannot * use the JavaScript method "getUserMedia" from "file:///android_assets/..." URLs. * 异步对WebView的操作 */

private SimpleWebServer mWebServer;

/** * A reference to the {@link WebView}. * 嵌入的ViewView */

private WebView mWebView;

/** * This field stores the {@link PermissionRequest} from the web application until it is allowed * or denied by user. * 授权行为 */

private PermissionRequest mPermissionRequest;

/** * For testing. * 控制台行为 */

private ConsoleMonitor mConsoleMonitor;

@Override

public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,

@Nullable Bundle savedInstanceState) {

//布局处理

return inflater.inflate(R.layout.fragment_permission_request, container, false);

}

@Override

public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {

//初始化WebView相关操作

mWebView = (WebView) view.findViewById(R.id.web_view);

// Here, we use #mWebChromeClient with implementation for handling PermissionRequests.

mWebView.setWebChromeClient(mWebChromeClient);

configureWebSettings(mWebView.getSettings());

}

@Override

public void onResume() {

super.onResume();

//模拟访问某URLWebView

final int port = 8080;

mWebServer = new SimpleWebServer(port, getResources().getAssets());

mWebServer.start();

mWebView.loadUrl("http://localhost:" + port + "/sample.html");

}

@Override

public void onPause() {

//关闭

mWebServer.stop();

super.onPause();

}

//允许JS操作行为

@SuppressLint("SetJavaScriptEnabled")

private static void configureWebSettings(WebSettings settings) {

settings.setJavaScriptEnabled(true);

}

/** * This {@link WebChromeClient} has implementation for handling {@link PermissionRequest}. * 主要的时间传递行为 */

private WebChromeClient mWebChromeClient = new WebChromeClient() {

// This method is called when the web content is requesting permission to access some

// resources.

//当网页内容被请求允许访问某些资源,调用此方法。

@Override

public void onPermissionRequest(PermissionRequest request) {

Log.i(TAG, "onPermissionRequest");

mPermissionRequest = request;

//把事件传递给了ConfirmationDialogFragment

ConfirmationDialogFragment.newInstance(request.getResources())

.show(getChildFragmentManager(), FRAGMENT_DIALOG);

}

// This method is called when the permission request is canceled by the web content.

//这个方法在授权请求被取消时被调用

@Override

public void onPermissionRequestCanceled(PermissionRequest request) {

Log.i(TAG, "onPermissionRequestCanceled");

// 驳回提示UI作为请求不再有效。

mPermissionRequest = null;

DialogFragment fragment = (DialogFragment) getChildFragmentManager()

.findFragmentByTag(FRAGMENT_DIALOG);

if (null != fragment) {

fragment.dismiss();

}

}

@Override

public boolean onConsoleMessage(@NonNull ConsoleMessage message) {

switch (message.messageLevel()) {

case TIP:

Log.v(TAG, message.message());

break;

case LOG:

Log.i(TAG, message.message());

break;

case WARNING:

Log.w(TAG, message.message());

break;

case ERROR:

Log.e(TAG, message.message());

break;

case DEBUG:

Log.d(TAG, message.message());

break;

}

if (null != mConsoleMonitor) {

mConsoleMonitor.onConsoleMessage(message);

}

return true;

}

};

@Override

public void onConfirmation(boolean allowed) {

if (allowed) {

mPermissionRequest.grant(mPermissionRequest.getResources());

Log.d(TAG, "Permission granted.");

} else {

mPermissionRequest.deny();

Log.d(TAG, "Permission request denied.");

}

mPermissionRequest = null;

}

public void setConsoleMonitor(ConsoleMonitor monitor) {

mConsoleMonitor = monitor;

}

/** * For testing. */

public interface ConsoleMonitor {

public void onConsoleMessage(ConsoleMessage message);

}} PermissionRequestFragment这个类做了一系列初始化的行为(主要是对于 WebView的),然后接收JS的回调,把处理的权限给予ConfirmationDialogFragment,然后根据ConfirmationDialogFragment的回调来做相关处理 再来看下ConfirmationDialogFragment /** * Prompts the user to confirm permission request. */public class ConfirmationDialogFragment extends DialogFragment {

private static final String ARG_RESOURCES = "resources";

/** * Creates a new instance of ConfirmationDialogFragment. * * @param resources The list of resources requested by PermissionRequeste. * @return A new instance. */

public static ConfirmationDialogFragment newInstance(String[] resources) {

ConfirmationDialogFragment fragment = new ConfirmationDialogFragment();

Bundle args = new Bundle();

args.putStringArray(ARG_RESOURCES, resources);

fragment.setArguments(args);

return fragment;

}

@Override

public Dialog onCreateDialog(Bundle savedInstanceState) {

String[] resources = getArguments().getStringArray(ARG_RESOURCES);

return new AlertDialog.Builder(getActivity())

.setMessage(getString(R.string.confirmation, TextUtils.join("\n", resources)))

.setNegativeButton(R.string.deny, new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

((Listener) getParentFragment()).onConfirmation(false);

}

})

.setPositiveButton(R.string.allow, new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

((Listener) getParentFragment()).onConfirmation(true);

}

})

.create();

}

/** * Callback for the user's response. */

public interface Listener {

/** * Called when the PermissoinRequest is allowed or denied by the user. * * @param allowed True if the user allowed the request. */

public void onConfirmation(boolean allowed);

}} 这边做的事情比较简单,就不在注释里讲了,这边笼统的介绍下。 首先当被调用的时候接受到了具体申请授权的内容,然后显示dialog,根据用户不同的操作传递给PermissionRequestFragment ,他本身不做什么具体授权行为,主要是dialog的显示功能。

@Override

public void onConfirmation(boolean allowed) {

if (allowed) {

mPermissionRequest.grant(mPermissionRequest.getResources());

Log.d(TAG, "Permission granted.");

} else {

mPermissionRequest.deny();

Log.d(TAG, "Permission request denied.");

}

mPermissionRequest = null;

} 因为在授权之后又再次为null,所以我们也就能反复对他进行操作了。 那么问题来了,从头到尾我们是如何跟JS交互的? 再来看下JS的代码 (function () { "use strict"; navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia; window.URL = window.URL || window.webkitURL; window.onload = function () { var video = document.querySelector('#video'), toggle = document.querySelector('#toggle'), stream = null; if (!navigator.getUserMedia) { console.error('getUserMedia not supported'); } toggle.addEventListener('click', function () { if (null === stream) { // This call to "getUserMedia" initiates a PermissionRequest in the WebView. navigator.getUserMedia({ video: true }, function (s) { stream = s; video.src = window.URL.createObjectURL(stream); toggle.innerText = 'Stop'; console.log('Started'); }, function (error) { console.error('Error starting camera. Denied.'); }); } else { stream.stop(); stream = null; toggle.innerText = 'Start'; console.log('Stopped'); } }); console.log('Page loaded'); }; })(); 整个html把事情都交付给了JS做逻辑判断 而navigator.getUserMedia 就是js向手机申请需要做某件事,手机知晓后向用户申请授权的代码了 里面还有一些读不到媒体干嘛干嘛的判断,大家爱看不看,不是太重要。 这样一来流程完全走了一遍 总结几个关键步骤: 1 WebView设置的时候要能接受JS请求 2 在需要native支持的时候通过双方的接口进行通信 3 手机接收到请求授权后问用户是否给予,如果用户不同意就 mPermissionRequest.deny() 代码那么多其实并不难理解,只是一大堆回调地狱而已! 源码地址:https://github.com/ddwhan0123/BlogSample/tree/master/PermissionRequest 源码下载地址:https://github.com/ddwhan0123/BlogSample/blob/master/PermissionRequest/PermissionRequest.zip?raw=true

原文

转载请注明出处:王亟亟的大牛之路 强行安利下自己的收纳库(日更):https://github.com/ddwhan0123/Useful-Open-Source-Android 昨天写了个CardView的貌似,不太受欢迎,今天上午没啥大事就继

------分隔线----------------------------
相关推荐