需求:系统连接WiFi时,若连接到需要登录的WiFi,则弹出登录页面。
说明:像 MIUI 等系统,现在的表现是弹出一个专门的页面(虽然我也不知道这个页面从哪儿能再次打开,以至于每次想更换账号都很费劲)。但是本文实现的是弹出一个普通的浏览器页面。
解决方案:在 NetworkMonitor.java 的 processMessage 中,当 Android 原生系统判断到需要登录时,发送 intent 打开任意网页,以使之自动重定向到登录页面。
NetworkMonitor.java 中这部分源码为:
508 @Override
509 public boolean processMessage(Message message) {
510 switch (message.what) {
511 case CMD_REEVALUATE:
512 if (message.arg1 != mReevaluateToken || mUserDoesNotWant)
513 return HANDLED;
514 // Don't bother validating networks that don't satisify the default request.
515 // This includes:
516 // - VPNs which can be considered explicitly desired by the user and the
517 // user's desire trumps whether the network validates.
518 // - Networks that don't provide internet access. It's unclear how to
519 // validate such networks.
520 // - Untrusted networks. It's unsafe to prompt the user to sign-in to
521 // such networks and the user didn't express interest in connecting to
522 // such networks (an app did) so the user may be unhappily surprised when
523 // asked to sign-in to a network they didn't want to connect to in the
524 // first place. Validation could be done to adjust the network scores
525 // however these networks are app-requested and may not be intended for
526 // general usage, in which case general validation may not be an accurate
527 // measure of the network's quality. Only the app knows how to evaluate
528 // the network so don't bother validating here. Furthermore sending HTTP
529 // packets over the network may be undesirable, for example an extremely
530 // expensive metered network, or unwanted leaking of the User Agent string.
531 if (!mDefaultRequest.networkCapabilities.satisfiedByNetworkCapabilities(
532 mNetworkAgentInfo.networkCapabilities)) {
533 validationLog("Network would not satisfy default request, not validating");
534 transitionTo(mValidatedState);
535 return HANDLED;
536 }
537 mAttempts++;
538 // Note: This call to isCaptivePortal() could take up to a minute. Resolving the
539 // server's IP addresses could hit the DNS timeout, and attempting connections
540 // to each of the server's several IP addresses (currently one IPv4 and one
541 // IPv6) could each take SOCKET_TIMEOUT_MS. During this time this StateMachine
542 // will be unresponsive. isCaptivePortal() could be executed on another Thread
543 // if this is found to cause problems.
544 CaptivePortalProbeResult probeResult = isCaptivePortal();
545 if (probeResult.isSuccessful()) {
546 transitionTo(mValidatedState);
547 } else if (probeResult.isPortal()) {
548 mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
549 NETWORK_TEST_RESULT_INVALID, mNetId, probeResult.redirectUrl));
550 mLastPortalProbeResult = probeResult;
551 transitionTo(mCaptivePortalState);
552 } else {
553 final Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
554 sendMessageDelayed(msg, mReevaluateDelayMs);
555 logNetworkEvent(NetworkEvent.NETWORK_VALIDATION_FAILED);
556 mConnectivityServiceHandler.sendMessage(obtainMessage(
557 EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, mNetId,
558 probeResult.redirectUrl));
559 if (mAttempts >= BLAME_FOR_EVALUATION_ATTEMPTS) {
560 // Don't continue to blame UID forever.
561 TrafficStats.clearThreadStatsUid();
562 }
563 mReevaluateDelayMs *= 2;
564 if (mReevaluateDelayMs > MAX_REEVALUATE_DELAY_MS) {
565 mReevaluateDelayMs = MAX_REEVALUATE_DELAY_MS;
566 }
567 }
568 return HANDLED;
569 case CMD_FORCE_REEVALUATION:
570 // Before IGNORE_REEVALUATE_ATTEMPTS attempts are made,
571 // ignore any re-evaluation requests. After, restart the
572 // evaluation process via EvaluatingState#enter.
573 return (mAttempts < IGNORE_REEVALUATE_ATTEMPTS) ? HANDLED : NOT_HANDLED;
574 default:
575 return NOT_HANDLED;
576 }
577 }
原理可见下方链接。大概意思是,当WiFi成功连接后,NetworkMonitor 会用一个 CaptivePortalProbeResult=isCaptivePortal()
来判断当前的网络是否是 需要登录验证的。并且给出了各种结果,第一种(probeResult.isSuccessful()
)是连接了需验证的WiFi,但已成功验证。第二种(probeResult.isPortal()
)正是我们需要的,需要验证的。因此,这段代码可以修改为如下内容:
CaptivePortalProbeResult probeResult = isCaptivePortal();
if (probeResult.isSuccessful()) {
transitionTo(mValidatedState);
} else if (probeResult.isPortal()) {
// Add by Enoch : Pop up window to log in portal wifi
Log.d(TAG, "ENOCH:::the wifi is CaptivePortal. start a browser with google.com");
Intent logIntent = new Intent();
logIntent.setAction("android.intent.action.VIEW");
logIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri urlDefault = Uri.parse("http://www.google.com");
logIntent.setData(urlDefault);
mContext.startActivityAsUser(logIntent, UserHandle.CURRENT_OR_SELF);
// Add by Enoch
mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
NETWORK_TEST_RESULT_INVALID, mNetId, probeResult.redirectUrl));
mLastPortalProbeResult = probeResult;
transitionTo(mCaptivePortalState);
} else {
关于 Android 网络连接评分机制 NetworkMonitor 的介绍,见: https://blog.csdn.net/u010961631/article/details/48971823
如果是通过应用实现此功能,而非在Android系统源码中进行修改,则见:https://blog.csdn.net/u012382509/article/details/53219991