fix: checkout code of closeWebView fix PR

This commit is contained in:
Rongjian Zhang 2019-02-12 00:22:58 +08:00
parent 97d61c055e
commit d25b979138
14 changed files with 498 additions and 2 deletions

View File

@ -4,6 +4,7 @@ import 'dart:async';
import 'package:http/http.dart' as http;
import 'package:uni_links/uni_links.dart';
import 'package:nanoid/nanoid.dart';
import 'package:url_launcher/url_launcher.dart';
// import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
@ -104,6 +105,11 @@ class _SettingsProviderState extends State<SettingsProvider> {
// https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/#web-application-flow
void _onSchemeDetected(Uri uri) async {
try {
// FIXME:
await closeWebView();
} catch (err) {}
setState(() {
loading = true;
});

View File

@ -76,7 +76,6 @@ class _LoginScreenState extends State<LoginScreen> {
var state = settings.generateRandomString();
launch(
'https://github.com/login/oauth/authorize?client_id=$clientId&redirect_uri=gittouch://login&scope=user%20repo&state=$state',
forceSafariVC: false, // this makes URL Scheme work
);
},
),

View File

@ -19,7 +19,8 @@ dependencies:
rxdart: ^0.20.0
uri: ^0.11.3
intl: ^0.15.7
url_launcher: ^4.2.0
url_launcher:
path: vendor/url_launcher
uni_links: ^0.1.4
flutter_markdown: ^0.2.0
shared_preferences: ^0.5.0

View File

@ -0,0 +1,34 @@
group 'io.flutter.plugins.urllauncher'
version '1.0-SNAPSHOT'
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
}
}
rootProject.allprojects {
repositories {
google()
jcenter()
}
}
apply plugin: 'com.android.library'
android {
compileSdkVersion 27
defaultConfig {
minSdkVersion 16
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
lintOptions {
disable 'InvalidPackage'
}
}

View File

@ -0,0 +1 @@
org.gradle.jvmargs=-Xmx1536M

View File

@ -0,0 +1 @@
rootProject.name = 'url_launcher'

View File

@ -0,0 +1,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.flutter.plugins.urllauncher">
<application>
<activity android:name=".UrlLauncherPlugin$WebViewActivity"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:exported="false"/>
</application>
</manifest>

View File

@ -0,0 +1,143 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package io.flutter.plugins.urllauncher;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Bundle;
import android.view.KeyEvent;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;
/** UrlLauncherPlugin */
public class UrlLauncherPlugin implements MethodCallHandler {
private final Registrar mRegistrar;
public static void registerWith(Registrar registrar) {
MethodChannel channel =
new MethodChannel(registrar.messenger(), "plugins.flutter.io/url_launcher");
UrlLauncherPlugin instance = new UrlLauncherPlugin(registrar);
channel.setMethodCallHandler(instance);
}
private UrlLauncherPlugin(Registrar registrar) {
this.mRegistrar = registrar;
}
@Override
public void onMethodCall(MethodCall call, Result result) {
String url = call.argument("url");
if (call.method.equals("canLaunch")) {
canLaunch(url, result);
} else if (call.method.equals("launch")) {
Intent launchIntent;
boolean useWebView = call.argument("useWebView");
boolean enableJavaScript = call.argument("enableJavaScript");
Activity activity = mRegistrar.activity();
if (activity == null) {
result.error("NO_ACTIVITY", "Launching a URL requires a foreground activity.", null);
return;
}
if (useWebView) {
launchIntent = new Intent(activity, WebViewActivity.class);
launchIntent.putExtra("url", url);
launchIntent.putExtra("enableJavaScript", enableJavaScript);
} else {
launchIntent = new Intent(Intent.ACTION_VIEW);
launchIntent.setData(Uri.parse(url));
}
activity.startActivity(launchIntent);
result.success(null);
} else if (call.method.equals("closeWebView")) {
Intent intent = new Intent("close");
mRegistrar.context().sendBroadcast(intent);
result.success(null);
} else {
result.notImplemented();
}
}
private void canLaunch(String url, Result result) {
Intent launchIntent = new Intent(Intent.ACTION_VIEW);
launchIntent.setData(Uri.parse(url));
ComponentName componentName =
launchIntent.resolveActivity(mRegistrar.context().getPackageManager());
boolean canLaunch =
componentName != null
&& !"{com.android.fallback/com.android.fallback.Fallback}"
.equals(componentName.toShortString());
result.success(canLaunch);
}
/* Launches WebView activity */
public static class WebViewActivity extends Activity {
private WebView webview;
private BroadcastReceiver broadcastReceiver;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
webview = new WebView(this);
setContentView(webview);
// Get the Intent that started this activity and extract the string
Intent intent = getIntent();
String url = intent.getStringExtra("url");
Boolean enableJavaScript = intent.getBooleanExtra("enableJavaScript", false);
webview.loadUrl(url);
if (enableJavaScript) {
webview.getSettings().setJavaScriptEnabled(enableJavaScript);
}
// Open new urls inside the webview itself.
webview.setWebViewClient(
new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
view.loadUrl(request.getUrl().toString());
return false;
}
});
// Set broadcast receiver to handle calls to close the web view
broadcastReceiver =
new BroadcastReceiver() {
@Override
public void onReceive(Context arg0, Intent intent) {
String action = intent.getAction();
if ("close".equals(action)) {
finish();
}
}
};
registerReceiver(broadcastReceiver, new IntentFilter("close"));
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(broadcastReceiver);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && webview.canGoBack()) {
webview.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
}
}

View File

View File

@ -0,0 +1,8 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import <Flutter/Flutter.h>
@interface FLTUrlLauncherPlugin : NSObject <FlutterPlugin>
@end

View File

@ -0,0 +1,147 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import <SafariServices/SafariServices.h>
#import "UrlLauncherPlugin.h"
@interface FLTUrlLaunchSession : NSObject <SFSafariViewControllerDelegate>
@property(strong) SFSafariViewController *safari;
@end
@implementation FLTUrlLaunchSession {
NSURL *_url;
FlutterResult _flutterResult;
void (^_completion)();
}
- (instancetype)initWithUrl:url withFlutterResult:result completion:completion {
self = [super init];
if (self) {
_url = url;
_flutterResult = result;
_safari = [[SFSafariViewController alloc] initWithURL:url];
_safari.delegate = self;
_completion = completion;
}
return self;
}
- (void)safariViewController:(SFSafariViewController *)controller
didCompleteInitialLoad:(BOOL)didLoadSuccessfully {
if (didLoadSuccessfully) {
_flutterResult(nil);
} else {
_flutterResult([FlutterError
errorWithCode:@"Error"
message:[NSString stringWithFormat:@"Error while launching %@", _url]
details:nil]);
}
}
- (void)safariViewControllerDidFinish:(SFSafariViewController *)controller {
[controller dismissViewControllerAnimated:YES completion:_completion];
}
- (void)close {
[self safariViewControllerDidFinish:_safari];
}
@end
@implementation FLTUrlLauncherPlugin {
UIViewController *_viewController;
FLTUrlLaunchSession *_currentSession;
}
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
FlutterMethodChannel *channel =
[FlutterMethodChannel methodChannelWithName:@"plugins.flutter.io/url_launcher"
binaryMessenger:registrar.messenger];
UIViewController *viewController =
[UIApplication sharedApplication].delegate.window.rootViewController;
FLTUrlLauncherPlugin *plugin =
[[FLTUrlLauncherPlugin alloc] initWithViewController:viewController];
[registrar addMethodCallDelegate:plugin channel:channel];
}
- (instancetype)initWithViewController:(UIViewController *)viewController {
self = [super init];
if (self) {
_viewController = viewController;
}
return self;
}
- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
NSString *url = call.arguments[@"url"];
if ([@"canLaunch" isEqualToString:call.method]) {
result(@([self canLaunchURL:url]));
} else if ([@"launch" isEqualToString:call.method]) {
NSNumber *useSafariVC = call.arguments[@"useSafariVC"];
if (useSafariVC.boolValue) {
[self launchURLInVC:url result:result];
} else {
[self launchURL:url result:result];
}
} else if ([@"closeWebView" isEqualToString:call.method]) {
[self closeWebView:url result:result];
} else {
result(FlutterMethodNotImplemented);
}
}
- (BOOL)canLaunchURL:(NSString *)urlString {
NSURL *url = [NSURL URLWithString:urlString];
UIApplication *application = [UIApplication sharedApplication];
return [application canOpenURL:url];
}
- (void)launchURL:(NSString *)urlString result:(FlutterResult)result {
NSURL *url = [NSURL URLWithString:urlString];
UIApplication *application = [UIApplication sharedApplication];
if ([application respondsToSelector:@selector(openURL:options:completionHandler:)]) {
[application openURL:url
options:@{}
completionHandler:^(BOOL success) {
if (success) {
result(nil);
} else {
result([FlutterError
errorWithCode:@"Error"
message:[NSString stringWithFormat:@"Error while launching %@", url]
details:nil]);
}
}];
} else {
BOOL success = [application openURL:url];
if (success) {
result(nil);
} else {
result([FlutterError
errorWithCode:@"Error"
message:[NSString stringWithFormat:@"Error while launching %@", url]
details:nil]);
}
}
}
- (void)launchURLInVC:(NSString *)urlString result:(FlutterResult)result {
NSURL *url = [NSURL URLWithString:urlString];
_currentSession = [[FLTUrlLaunchSession alloc] initWithUrl:url
withFlutterResult:result
completion:^void() {
self->_currentSession = nil;
}];
[_viewController presentViewController:_currentSession.safari animated:YES completion:nil];
}
- (void)closeWebView:(NSString *)urlString result:(FlutterResult)result {
if (_currentSession != nil) {
[_currentSession close];
}
result(nil);
}
@end

View File

@ -0,0 +1,21 @@
#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
#
Pod::Spec.new do |s|
s.name = 'url_launcher'
s.version = '0.0.1'
s.summary = 'Flutter plugin for launching a URL.'
s.description = <<-DESC
A Flutter plugin for making the underlying platform (Android or iOS) launch a URL.
DESC
s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/url_launcher'
s.license = { :file => '../LICENSE' }
s.author = { 'Flutter Team' => 'flutter-dev@googlegroups.com' }
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.public_header_files = 'Classes/**/*.h'
s.dependency 'Flutter'
s.ios.deployment_target = '8.0'
end

View File

@ -0,0 +1,103 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
const MethodChannel _channel = MethodChannel('plugins.flutter.io/url_launcher');
/// Parses the specified URL string and delegates handling of it to the
/// underlying platform.
///
/// The returned future completes with a [PlatformException] on invalid URLs and
/// schemes which cannot be handled, that is when [canLaunch] would complete
/// with false.
///
/// [forceSafariVC] is only used in iOS. If unset, the launcher opens web URLs
/// in the safari VC, anything else is opened using the default handler on the
/// platform. If set to true, it opens the URL in the Safari view controller.
/// If false, the URL is opened in the default browser of the phone. Set this to
/// false if you want to use the cookies/context of the main browser of the app
/// (such as SSO flows).
///
/// [forceWebView] is an Android only setting. If null or false, the URL is
/// always launched with the default browser on device. If set to true, the URL
/// is launched in a webview. Unlike iOS, browser context is shared across
/// WebViews.
/// [enableJavaScript] is an Android only setting. If true, webview enable
/// javascript.
///
/// Note that if any of the above are set to true but the URL is not a web URL,
/// this will throw a [PlatformException].
///
/// [statusBarBrightness] Sets the status bar brightness of the application
/// after opening a link on iOS. Does nothing if no value is passed. This does
/// not handle reseting the previous status bar style.
Future<void> launch(
String urlString, {
bool forceSafariVC,
bool forceWebView,
bool enableJavaScript,
Brightness statusBarBrightness,
}) {
assert(urlString != null);
final Uri url = Uri.parse(urlString.trimLeft());
final bool isWebURL = url.scheme == 'http' || url.scheme == 'https';
if ((forceSafariVC == true || forceWebView == true) && !isWebURL) {
throw PlatformException(
code: 'NOT_A_WEB_SCHEME',
message: 'To use webview or safariVC, you need to pass'
'in a web URL. This $urlString is not a web URL.');
}
bool previousAutomaticSystemUiAdjustment;
if (statusBarBrightness != null &&
defaultTargetPlatform == TargetPlatform.iOS) {
previousAutomaticSystemUiAdjustment =
WidgetsBinding.instance.renderView.automaticSystemUiAdjustment;
WidgetsBinding.instance.renderView.automaticSystemUiAdjustment = false;
SystemChrome.setSystemUIOverlayStyle(statusBarBrightness == Brightness.light
? SystemUiOverlayStyle.dark
: SystemUiOverlayStyle.light);
}
return _channel.invokeMethod(
'launch',
<String, Object>{
'url': urlString,
'useSafariVC': forceSafariVC ?? isWebURL,
'useWebView': forceWebView ?? false,
'enableJavaScript': enableJavaScript ?? false,
},
).then((void _) {
if (statusBarBrightness != null) {
WidgetsBinding.instance.renderView.automaticSystemUiAdjustment =
previousAutomaticSystemUiAdjustment;
}
});
}
/// Checks whether the specified URL can be handled by some app installed on the
/// device.
Future<bool> canLaunch(String urlString) async {
if (urlString == null) {
return false;
}
return await _channel.invokeMethod(
'canLaunch',
<String, Object>{'url': urlString},
);
}
/// Closes the current WebView, if one was previously opened via a call to [launch].
///
/// If [launch] was never called, then this call will not have any effect.
///
/// On Android systems, if [launch] was called without `forceWebView` being set to
/// `true`, this call will not do anything either, simply because there is no
/// WebView available to be closed.
Future<void> closeWebView() async {
return await _channel.invokeMethod('closeWebView');
}

24
vendor/url_launcher/pubspec.yaml vendored Normal file
View File

@ -0,0 +1,24 @@
name: url_launcher
description: Flutter plugin for launching a URL on Android and iOS. Supports
web, phone, SMS, and email schemes.
author: Flutter Team <flutter-dev@googlegroups.com>
homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher
version: 4.0.3
flutter:
plugin:
androidPackage: io.flutter.plugins.urllauncher
iosPrefix: FLT
pluginClass: UrlLauncherPlugin
dependencies:
flutter:
sdk: flutter
dev_dependencies:
flutter_test:
sdk: flutter
environment:
sdk: ">=2.0.0-dev.28.0 <3.0.0"
flutter: ">=0.5.6 <2.0.0"