Commit 5c402c09 authored by 李增强's avatar 李增强

Initial commit

parents
## 5.7.10
* Update Dart SDK constraint in example.
## 5.7.9
* Check in windows/ directory for example/
## 5.7.8
* Fixed a situation where an app would crash if the url_launcher’s `launch` method can’t find an app to open the provided url. It will now throw a clear Dart PlatformException.
## 5.7.7
* Introduce the Link widget with an implementation for native platforms.
## 5.7.6
* Suppress deprecation warning on the `shouldOverrideUrlLoading` method on Android of the `FlutterWebChromeClient` class.
## 5.7.5
* Improved documentation of the `headers` parameter.
## 5.7.4
* Update android compileSdkVersion to 29.
## 5.7.3
* Check in linux/ directory for example/
## 5.7.2
* Add API documentation explaining the [canLaunch] method returns `false` if package visibility (Android API 30) is not managed correctly.
## 5.7.1
* Keep handling deprecated Android v1 classes for backward compatibility.
## 5.7.0
* Handle WebView multi-window support.
## 5.6.0
* Support Windows by default.
## 5.5.3
* Suppress deprecation warning on the `shouldOverrideUrlLoading` method on Android.
## 5.5.2
* Depend explicitly on the `platform_interface` package that adds the `webOnlyWindowName` parameter.
## 5.5.1
* Added webOnlyWindowName parameter to launch()
## 5.5.0
* Support Linux by default.
## 5.4.11
* Add documentation in README suggesting how to properly encode urls with special characters.
## 5.4.10
* Post-v2 Android embedding cleanups.
## 5.4.9
* Update README.
## 5.4.8
* Initialize `previousAutomaticSystemUiAdjustment` in launch method.
## 5.4.7
* Update lower bound of dart dependency to 2.1.0.
## 5.4.6
* Add `web` to the example app.
## 5.4.5
* Remove Android dependencies fallback.
* Require Flutter SDK 1.12.13+hotfix.5 or greater.
* Fix CocoaPods podspec lint warnings.
## 5.4.4
* Replace deprecated `getFlutterEngine` call on Android.
## 5.4.3
* Fixed the launchUniversalLinkIos method.
## 5.4.2
* Make the pedantic dev_dependency explicit.
## 5.4.1
* Update unit tests to work with the PlatformInterface from package `plugin_platform_interface`.
## 5.4.0
* Support macOS by default.
## 5.3.0
* Support web by default.
* Use the new plugins pubspec schema.
## 5.2.7
* Minor unit test changes and added a lint for public DartDocs.
## 5.2.6
* Remove AndroidX warnings.
## 5.2.5
* Include lifecycle dependency as a compileOnly one on Android to resolve
potential version conflicts with other transitive libraries.
## 5.2.4
* Use `package:url_launcher_platform_interface` to get the platform-specific implementation.
## 5.2.3
* Android: Use android.arch.lifecycle instead of androidx.lifecycle:lifecycle in `build.gradle` to support apps that has not been migrated to AndroidX.
## 5.2.2
* Re-land embedder v2 support with correct Flutter SDK constraints.
## 5.2.1
* Revert the migration since the Flutter dependency was too low.
## 5.2.0
* Migrate the plugin to use the V2 Android engine embedding. This shouldn't
affect existing functionality. Plugin authors who use the V2 embedding can now
instantiate the plugin and expect that it correctly responds to app lifecycle
changes.
## 5.1.7
* Define clang module for iOS.
## 5.1.6
* Fixes bug where androidx app won't build with this plugin by enabling androidx and jetifier in the android `gradle.properties`.
## 5.1.5
* Update homepage url after moving to federated directory.
## 5.1.4
* Update and migrate iOS example project.
## 5.1.3
* Always launch url from the top most UIViewController in iOS.
## 5.1.2
* Update AGP and gradle.
* Split plugin and WebViewActivity class files.
## 5.1.1
* Suppress a handled deprecation warning on iOS
## 5.1.0
* Add `headers` field to enable headers in the Android implementation.
## 5.0.5
* Add `enableDomStorage` field to `launch` to enable DOM storage in Android WebView.
## 5.0.4
* Update Dart code to conform to current Dart formatter.
## 5.0.3
* Add missing template type parameter to `invokeMethod` calls.
* Bump minimum Flutter version to 1.5.0.
* Replace invokeMethod with invokeMapMethod wherever necessary.
## 5.0.2
* Fixes `closeWebView` failure on iOS.
## 5.0.1
* Log a more detailed warning at build time about the previous AndroidX
migration.
## 5.0.0
* **Breaking change**. Migrate from the deprecated original Android Support
Library to AndroidX. This shouldn't result in any functional changes, but it
requires any Android apps using this plugin to [also
migrate](https://developer.android.com/jetpack/androidx/migrate) if they're
using the original support library.
This was originally incorrectly pushed in the `4.2.0` update.
## 4.2.0+3
* **Revert the breaking 4.2.0 update**. 4.2.0 was known to be breaking and
should have incremented the major version number instead of the minor. This
revert is in and of itself breaking for anyone that has already migrated
however. Anyone who has already migrated their app to AndroidX should
immediately update to `5.0.0` instead. That's the correctly versioned new push
of `4.2.0`.
## 4.2.0+2
* Updated `launch` to use async and await, fixed the incorrect return value by `launch` method.
## 4.2.0+1
* Refactored the Java and Objective-C code. Replaced instance variables with properties in Objective-C.
## 4.2.0
* **BAD**. This was a breaking change that was incorrectly published on a minor
version upgrade, should never have happened. Reverted by 4.2.0+3.
* **Breaking change**. Migrate from the deprecated original Android Support
Library to AndroidX. This shouldn't result in any functional changes, but it
requires any Android apps using this plugin to [also
migrate](https://developer.android.com/jetpack/androidx/migrate) if they're
using the original support library.
## 4.1.0+1
* This is just a version bump to republish as 4.1.0 was published with some dirty local state.
## 4.1.0
* Added `universalLinksOnly` setting.
* Updated `launch` to return `Future<bool>`.
## 4.0.3
* Fixed launch url fail for Android: `launch` now assert activity not null and using activity to startActivity.
* Fixed `WebViewActivity has leaked IntentReceiver` for Android.
## 4.0.2
* Added `closeWebView` function to programmatically close the current WebView.
## 4.0.1
* Added enableJavaScript field to `launch` to enable javascript in Android WebView.
## 4.0.0
* **Breaking change** Now requires a minimum Flutter version of 0.5.6.
* Update to statusBarBrightness field so that the logic runs on the Flutter side.
* **Breaking change** statusBarBrightness no longer has a default value.
## 3.0.3
* Added statusBarBrightness field to `launch` to set iOS status bar brightness.
## 3.0.2
* Updated Gradle tooling to match Android Studio 3.1.2.
## 3.0.1
* Fix a crash during Safari view controller dismiss.
## 3.0.0
* **Breaking change**. Set SDK constraints to match the Flutter beta release.
## 2.0.2
* Fixed Dart 2 issue: `launch` now returns `Future<void>` instead of
`Future<Null>`.
## 2.0.1
* Simplified and upgraded Android project template to Android SDK 27.
* Updated package description.
## 2.0.0
* **Breaking change**. Upgraded to Gradle 4.1 and Android Studio Gradle plugin
3.0.1. Older Flutter projects need to upgrade their Gradle setup as well in
order to use this version of the plugin. Instructions can be found
[here](https://github.com/flutter/flutter/wiki/Updating-Flutter-projects-to-Gradle-4.1-and-Android-Studio-Gradle-plugin-3.0.1).
## 1.0.3
* Add FLT prefix to iOS types.
## 1.0.2
* Fix handling of URLs in Android WebView.
## 1.0.1
* Support option to launch default browser in iOS.
* Parse incoming url and decide on what to open based on scheme.
* Support WebView on Android.
## 1.0.0
* iOS plugin presents a Safari view controller instead of switching to the Safari app.
## 0.4.2+5
* Aligned author name with rest of repo.
## 0.4.2+2, 0.4.2+3, 0.4.2+4
* Updated README.
## 0.4.2+1
* Updated README.
## 0.4.2
* Change to README.md.
## 0.4.1
* Upgrade Android SDK Build Tools to 25.0.3.
## 0.4.0
* Upgrade to new plugin registration.
## 0.3.6
* Fix workaround for failing dynamic check in Xcode 7/sdk version 9.
## 0.3.5
* Workaround for failing dynamic check in Xcode 7/sdk version 9.
## 0.3.4
* Add test.
## 0.3.3
* Change to buildToolsVersion.
## 0.3.2
* Change to README.md.
## 0.3.1
* Change to README.md.
## 0.3.0
* Add `canLaunch` method.
## 0.2.0
* Change `launch` to a top-level method instead of a static method in a class.
## 0.1.1
* Change to README.md.
## 0.1.0
* Initial Open Source release.
Copyright 2017 The Chromium Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# url_launcher
[![pub package](https://img.shields.io/pub/v/url_launcher.svg)](https://pub.dartlang.org/packages/url_launcher)
A Flutter plugin for launching a URL in the mobile platform. Supports
iOS, Android, web, Windows, macOS, and Linux.
## Usage
To use this plugin, add `url_launcher` as a [dependency in your pubspec.yaml file](https://flutter.dev/platform-plugins/).
### Example
``` dart
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
void main() {
runApp(Scaffold(
body: Center(
child: RaisedButton(
onPressed: _launchURL,
child: Text('Show Flutter homepage'),
),
),
));
}
_launchURL() async {
const url = 'https://flutter.dev';
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
```
## Supported URL schemes
The [`launch`](https://www.dartdocs.org/documentation/url_launcher/latest/url_launcher/launch.html) method
takes a string argument containing a URL. This URL
can be formatted using a number of different URL schemes. The supported
URL schemes depend on the underlying platform and installed apps.
Common schemes supported by both iOS and Android:
| Scheme | Action |
|---|---|
| `http:<URL>` , `https:<URL>`, e.g. `http://flutter.dev` | Open URL in the default browser |
| `mailto:<email address>?subject=<subject>&body=<body>`, e.g. `mailto:smith@example.org?subject=News&body=New%20plugin` | Create email to <email address> in the default email app |
| `tel:<phone number>`, e.g. `tel:+1 555 010 999` | Make a phone call to <phone number> using the default phone app |
| `sms:<phone number>`, e.g. `sms:5550101234` | Send an SMS message to <phone number> using the default messaging app |
More details can be found here for [iOS](https://developer.apple.com/library/content/featuredarticles/iPhoneURLScheme_Reference/Introduction/Introduction.html) and [Android](https://developer.android.com/guide/components/intents-common.html)
### Encoding URLs
URLs must be properly encoded, especially when including spaces or other special characters. This can be done using the [`Uri` class](https://api.dart.dev/stable/2.7.1/dart-core/Uri-class.html):
```dart
import 'dart:core';
import 'package:url_launcher/url_launcher.dart';
final Uri _emailLaunchUri = Uri(
scheme: 'mailto',
path: 'smith@example.com',
queryParameters: {
'subject': 'Example Subject & Symbols are allowed!'
}
);
// ...
// mailto:smith@example.com?subject=Example+Subject+%26+Symbols+are+allowed%21
launch(_emailLaunchUri.toString());
```
## Handling missing URL receivers
A particular mobile device may not be able to receive all supported URL schemes.
For example, a tablet may not have a cellular radio and thus no support for
launching a URL using the `sms` scheme, or a device may not have an email app
and thus no support for launching a URL using the `email` scheme.
We recommend checking which URL schemes are supported using the
[`canLaunch`](https://www.dartdocs.org/documentation/url_launcher/latest/url_launcher/canLaunch.html)
method prior to calling `launch`. If the `canLaunch` method returns false, as a
best practice we suggest adjusting the application UI so that the unsupported
URL is never triggered; for example, if the `email` scheme is not supported, a
UI button that would have sent email can be changed to redirect the user to a
web page using a URL following the `http` scheme.
## Browser vs In-app Handling
By default, Android opens up a browser when handling URLs. You can pass
`forceWebView: true` parameter to tell the plugin to open a WebView instead.
If you do this for a URL of a page containing JavaScript, make sure to pass in
`enableJavaScript: true`, or else the launch method will not work properly. On
iOS, the default behavior is to open all web URLs within the app. Everything
else is redirected to the app handler.
group 'io.flutter.plugins.urllauncher'
version '1.0-SNAPSHOT'
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.2'
}
}
rootProject.allprojects {
repositories {
google()
jcenter()
}
}
apply plugin: 'com.android.library'
android {
compileSdkVersion 29
defaultConfig {
minSdkVersion 16
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
lintOptions {
disable 'InvalidPackage'
}
testOptions {
unitTests.includeAndroidResources = true
}
}
dependencies {
compileOnly 'androidx.annotation:annotation:1.0.0'
testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:1.10.19'
testImplementation 'androidx.test:core:1.0.0'
testImplementation 'org.robolectric:robolectric:4.3'
}
org.gradle.jvmargs=-Xmx1536M
rootProject.name = 'url_launcher'
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.flutter.plugins.urllauncher">
<application>
<activity android:name="io.flutter.plugins.urllauncher.WebViewActivity"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:exported="false"/>
</application>
</manifest>
package io.flutter.plugins.urllauncher;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.Nullable;
import io.flutter.plugin.common.BinaryMessenger;
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.plugins.urllauncher.UrlLauncher.LaunchStatus;
import java.util.Map;
/**
* Translates incoming UrlLauncher MethodCalls into well formed Java function calls for {@link
* UrlLauncher}.
*/
final class MethodCallHandlerImpl implements MethodCallHandler {
private static final String TAG = "MethodCallHandlerImpl";
private final UrlLauncher urlLauncher;
@Nullable private MethodChannel channel;
/** Forwards all incoming MethodChannel calls to the given {@code urlLauncher}. */
MethodCallHandlerImpl(UrlLauncher urlLauncher) {
this.urlLauncher = urlLauncher;
}
@Override
public void onMethodCall(MethodCall call, Result result) {
final String url = call.argument("url");
switch (call.method) {
case "canLaunch":
onCanLaunch(result, url);
break;
case "launch":
onLaunch(call, result, url);
break;
case "closeWebView":
onCloseWebView(result);
break;
default:
result.notImplemented();
break;
}
}
/**
* Registers this instance as a method call handler on the given {@code messenger}.
*
* <p>Stops any previously started and unstopped calls.
*
* <p>This should be cleaned with {@link #stopListening} once the messenger is disposed of.
*/
void startListening(BinaryMessenger messenger) {
if (channel != null) {
Log.wtf(TAG, "Setting a method call handler before the last was disposed.");
stopListening();
}
channel = new MethodChannel(messenger, "plugins.flutter.io/url_launcher");
channel.setMethodCallHandler(this);
}
/**
* Clears this instance from listening to method calls.
*
* <p>Does nothing if {@link #startListening} hasn't been called, or if we're already stopped.
*/
void stopListening() {
if (channel == null) {
Log.d(TAG, "Tried to stop listening when no MethodChannel had been initialized.");
return;
}
channel.setMethodCallHandler(null);
channel = null;
}
private void onCanLaunch(Result result, String url) {
result.success(urlLauncher.canLaunch(url));
}
private void onLaunch(MethodCall call, Result result, String url) {
final boolean useWebView = call.argument("useWebView");
final boolean enableJavaScript = call.argument("enableJavaScript");
final boolean enableDomStorage = call.argument("enableDomStorage");
final Map<String, String> headersMap = call.argument("headers");
final Bundle headersBundle = extractBundle(headersMap);
LaunchStatus launchStatus =
urlLauncher.launch(url, headersBundle, useWebView, enableJavaScript, enableDomStorage);
if (launchStatus == LaunchStatus.NO_ACTIVITY) {
result.error("NO_ACTIVITY", "Launching a URL requires a foreground activity.", null);
} else if (launchStatus == LaunchStatus.ACTIVITY_NOT_FOUND) {
result.error(
"ACTIVITY_NOT_FOUND",
String.format("No Activity found to handle intent { %s }", url),
null);
} else {
result.success(true);
}
}
private void onCloseWebView(Result result) {
urlLauncher.closeWebView();
result.success(null);
}
private static Bundle extractBundle(Map<String, String> headersMap) {
final Bundle headersBundle = new Bundle();
for (String key : headersMap.keySet()) {
final String value = headersMap.get(key);
headersBundle.putString(key, value);
}
return headersBundle;
}
}
package io.flutter.plugins.urllauncher;
import android.app.Activity;
import android.app.Application;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Browser;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/**
* Launches components for URLs.
*/
class UrlLauncher {
private final Context applicationContext;
@Nullable
private Activity mCurrentActiveActivity;
/**
* Uses the given {@code applicationContext} for launching intents.
*
* <p>It may be null initially, but should be set before calling {@link #launch}.
*/
UrlLauncher(Context applicationContext, @Nullable Activity activity) {
this.applicationContext = applicationContext;
this.mCurrentActiveActivity = activity;
if (activity != null) {
abActivity(activity);
}
}
void setmCurrentActiveActivity(@Nullable Activity activity) {
if (this.mCurrentActiveActivity != null) {
return;
}
this.mCurrentActiveActivity = activity;
abActivity(activity);
}
void abActivity(Activity activity) {
activity.getApplication().registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
mCurrentActiveActivity = activity;
}
@Override
public void onActivityStarted(Activity activity) {
mCurrentActiveActivity = activity;
}
@Override
public void onActivityResumed(Activity activity) {
mCurrentActiveActivity = activity;
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
if (mCurrentActiveActivity == activity) {
mCurrentActiveActivity = null;
}
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
if (mCurrentActiveActivity == activity) {
mCurrentActiveActivity = null;
}
}
});
}
/**
* Returns whether the given {@code url} resolves into an existing component.
*/
boolean canLaunch(String url) {
Intent launchIntent = new Intent(Intent.ACTION_VIEW);
launchIntent.setData(Uri.parse(url));
ComponentName componentName =
launchIntent.resolveActivity(applicationContext.getPackageManager());
return componentName != null
&& !"{com.android.fallback/com.android.fallback.Fallback}"
.equals(componentName.toShortString());
}
/**
* Attempts to launch the given {@code url}.
*
* @param headersBundle forwarded to the intent as {@code Browser.EXTRA_HEADERS}.
* @param useWebView when true, the URL is launched inside of {@link WebViewActivity}.
* @param enableJavaScript Only used if {@param useWebView} is true. Enables JS in the WebView.
* @param enableDomStorage Only used if {@param useWebView} is true. Enables DOM storage in the
* @return {@link LaunchStatus#NO_ACTIVITY} if there's no available {@code applicationContext}.
* {@link LaunchStatus#ACTIVITY_NOT_FOUND} if there's no activity found to handle {@code
* launchIntent}. {@link LaunchStatus#OK} otherwise.
*/
LaunchStatus launch(
String url,
Bundle headersBundle,
boolean useWebView,
boolean enableJavaScript,
boolean enableDomStorage) {
if (mCurrentActiveActivity == null) {
return LaunchStatus.NO_ACTIVITY;
}
Intent launchIntent;
if (useWebView) {
launchIntent =
WebViewActivity.createIntent(
mCurrentActiveActivity, url, enableJavaScript, enableDomStorage, headersBundle);
} else {
launchIntent =
new Intent(Intent.ACTION_VIEW)
.setData(Uri.parse(url))
.putExtra(Browser.EXTRA_HEADERS, headersBundle);
}
try {
mCurrentActiveActivity.startActivity(launchIntent);
} catch (ActivityNotFoundException e) {
return LaunchStatus.ACTIVITY_NOT_FOUND;
}
return LaunchStatus.OK;
}
/**
* Closes any activities started with {@link #launch} {@code useWebView=true}.
*/
void closeWebView() {
applicationContext.sendBroadcast(new Intent(WebViewActivity.ACTION_CLOSE));
}
/**
* Result of a {@link #launch} call.
*/
enum LaunchStatus {
/**
* The intent was well formed.
*/
OK,
/**
* No activity was found to launch.
*/
NO_ACTIVITY,
/**
* No Activity found that can handle given intent.
*/
ACTIVITY_NOT_FOUND,
}
}
package io.flutter.plugins.urllauncher;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
/**
* Plugin implementation that uses the new {@code io.flutter.embedding} package.
*
* <p>Instantiate this in an add to app scenario to gracefully handle activity and context changes.
*/
public final class UrlLauncherPlugin implements FlutterPlugin, ActivityAware {
private static final String TAG = "UrlLauncherPlugin";
@Nullable private MethodCallHandlerImpl methodCallHandler;
@Nullable private UrlLauncher urlLauncher;
/**
* Registers a plugin implementation that uses the stable {@code io.flutter.plugin.common}
* package.
*
* <p>Calling this automatically initializes the plugin. However plugins initialized this way
* won't react to changes in activity or context, unlike {@link UrlLauncherPlugin}.
*/
@SuppressWarnings("deprecation")
public static void registerWith(io.flutter.plugin.common.PluginRegistry.Registrar registrar) {
MethodCallHandlerImpl handler =
new MethodCallHandlerImpl(new UrlLauncher(registrar.context(), registrar.activity()));
handler.startListening(registrar.messenger());
}
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
urlLauncher = new UrlLauncher(binding.getApplicationContext(), /*activity=*/ null);
methodCallHandler = new MethodCallHandlerImpl(urlLauncher);
methodCallHandler.startListening(binding.getBinaryMessenger());
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
if (methodCallHandler == null) {
Log.wtf(TAG, "Already detached from the engine.");
return;
}
methodCallHandler.stopListening();
methodCallHandler = null;
urlLauncher = null;
}
@Override
public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
if (methodCallHandler == null) {
Log.wtf(TAG, "urlLauncher was never set.");
return;
}
urlLauncher.setmCurrentActiveActivity(binding.getActivity());
}
@Override
public void onDetachedFromActivity() {
if (methodCallHandler == null) {
Log.wtf(TAG, "urlLauncher was never set.");
return;
}
urlLauncher.setmCurrentActiveActivity(null);
}
@Override
public void onDetachedFromActivityForConfigChanges() {
onDetachedFromActivity();
}
@Override
public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {
onAttachedToActivity(binding);
}
}
package io.flutter.plugins.urllauncher;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Bundle;
import android.os.Message;
import android.provider.Browser;
import android.view.KeyEvent;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import java.util.HashMap;
import java.util.Map;
/* Launches WebView activity */
public class WebViewActivity extends Activity {
/*
* Use this to trigger a BroadcastReceiver inside WebViewActivity
* that will request the current instance to finish.
* */
public static String ACTION_CLOSE = "close action";
private final BroadcastReceiver broadcastReceiver =
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_CLOSE.equals(action)) {
finish();
}
}
};
private final WebViewClient webViewClient =
new WebViewClient() {
/*
* This method is deprecated in API 24. Still overridden to support
* earlier Android versions.
*/
@SuppressWarnings("deprecation")
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
view.loadUrl(url);
return false;
}
return super.shouldOverrideUrlLoading(view, url);
}
@RequiresApi(Build.VERSION_CODES.N)
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
view.loadUrl(request.getUrl().toString());
}
return false;
}
};
private WebView webview;
private IntentFilter closeIntentFilter = new IntentFilter(ACTION_CLOSE);
// Verifies that a url opened by `Window.open` has a secure url.
private class FlutterWebChromeClient extends WebChromeClient {
@Override
public boolean onCreateWindow(
final WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
final WebViewClient webViewClient =
new WebViewClient() {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean shouldOverrideUrlLoading(
@NonNull WebView view, @NonNull WebResourceRequest request) {
webview.loadUrl(request.getUrl().toString());
return true;
}
/*
* This method is deprecated in API 24. Still overridden to support
* earlier Android versions.
*/
@SuppressWarnings("deprecation")
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
webview.loadUrl(url);
return true;
}
};
final WebView newWebView = new WebView(webview.getContext());
newWebView.setWebViewClient(webViewClient);
final WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
transport.setWebView(newWebView);
resultMsg.sendToTarget();
return true;
}
}
@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
final Intent intent = getIntent();
final String url = intent.getStringExtra(URL_EXTRA);
final boolean enableJavaScript = intent.getBooleanExtra(ENABLE_JS_EXTRA, false);
final boolean enableDomStorage = intent.getBooleanExtra(ENABLE_DOM_EXTRA, false);
final Bundle headersBundle = intent.getBundleExtra(Browser.EXTRA_HEADERS);
final Map<String, String> headersMap = extractHeaders(headersBundle);
webview.loadUrl(url, headersMap);
webview.getSettings().setJavaScriptEnabled(enableJavaScript);
webview.getSettings().setDomStorageEnabled(enableDomStorage);
// Open new urls inside the webview itself.
webview.setWebViewClient(webViewClient);
// Multi windows is set with FlutterWebChromeClient by default to handle internal bug: b/159892679.
webview.getSettings().setSupportMultipleWindows(true);
webview.setWebChromeClient(new FlutterWebChromeClient());
// Register receiver that may finish this Activity.
registerReceiver(broadcastReceiver, closeIntentFilter);
}
private Map<String, String> extractHeaders(Bundle headersBundle) {
final Map<String, String> headersMap = new HashMap<>();
for (String key : headersBundle.keySet()) {
final String value = headersBundle.getString(key);
headersMap.put(key, value);
}
return headersMap;
}
@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);
}
private static String URL_EXTRA = "url";
private static String ENABLE_JS_EXTRA = "enableJavaScript";
private static String ENABLE_DOM_EXTRA = "enableDomStorage";
/* Hides the constants used to forward data to the Activity instance. */
public static Intent createIntent(
Context context,
String url,
boolean enableJavaScript,
boolean enableDomStorage,
Bundle headersBundle) {
return new Intent(context, WebViewActivity.class)
.putExtra(URL_EXTRA, url)
.putExtra(ENABLE_JS_EXTRA, enableJavaScript)
.putExtra(ENABLE_DOM_EXTRA, enableDomStorage)
.putExtra(Browser.EXTRA_HEADERS, headersBundle);
}
}
package io.flutter.plugins.urllauncher;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.os.Bundle;
import androidx.test.core.app.ApplicationProvider;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.BinaryMessenger.BinaryMessageHandler;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel.Result;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
public class MethodCallHandlerImplTest {
private static final String CHANNEL_NAME = "plugins.flutter.io/url_launcher";
private UrlLauncher urlLauncher;
private MethodCallHandlerImpl methodCallHandler;
@Before
public void setUp() {
urlLauncher = new UrlLauncher(ApplicationProvider.getApplicationContext(), /*activity=*/ null);
methodCallHandler = new MethodCallHandlerImpl(urlLauncher);
}
@Test
public void startListening_registersChannel() {
BinaryMessenger messenger = mock(BinaryMessenger.class);
methodCallHandler.startListening(messenger);
verify(messenger, times(1))
.setMessageHandler(eq(CHANNEL_NAME), any(BinaryMessageHandler.class));
}
@Test
public void startListening_unregistersExistingChannel() {
BinaryMessenger firstMessenger = mock(BinaryMessenger.class);
BinaryMessenger secondMessenger = mock(BinaryMessenger.class);
methodCallHandler.startListening(firstMessenger);
methodCallHandler.startListening(secondMessenger);
// Unregisters the first and then registers the second.
verify(firstMessenger, times(1)).setMessageHandler(CHANNEL_NAME, null);
verify(secondMessenger, times(1))
.setMessageHandler(eq(CHANNEL_NAME), any(BinaryMessageHandler.class));
}
@Test
public void stopListening_unregistersExistingChannel() {
BinaryMessenger messenger = mock(BinaryMessenger.class);
methodCallHandler.startListening(messenger);
methodCallHandler.stopListening();
verify(messenger, times(1)).setMessageHandler(CHANNEL_NAME, null);
}
@Test
public void stopListening_doesNothingWhenUnset() {
BinaryMessenger messenger = mock(BinaryMessenger.class);
methodCallHandler.stopListening();
verify(messenger, never()).setMessageHandler(CHANNEL_NAME, null);
}
@Test
public void onMethodCall_canLaunchReturnsTrue() {
urlLauncher = mock(UrlLauncher.class);
methodCallHandler = new MethodCallHandlerImpl(urlLauncher);
String url = "foo";
when(urlLauncher.canLaunch(url)).thenReturn(true);
Result result = mock(Result.class);
Map<String, Object> args = new HashMap<>();
args.put("url", url);
methodCallHandler.onMethodCall(new MethodCall("canLaunch", args), result);
verify(result, times(1)).success(true);
}
@Test
public void onMethodCall_canLaunchReturnsFalse() {
urlLauncher = mock(UrlLauncher.class);
methodCallHandler = new MethodCallHandlerImpl(urlLauncher);
String url = "foo";
when(urlLauncher.canLaunch(url)).thenReturn(false);
Result result = mock(Result.class);
Map<String, Object> args = new HashMap<>();
args.put("url", url);
methodCallHandler.onMethodCall(new MethodCall("canLaunch", args), result);
verify(result, times(1)).success(false);
}
@Test
public void onMethodCall_launchReturnsNoActivityError() {
// Setup mock objects
urlLauncher = mock(UrlLauncher.class);
Result result = mock(Result.class);
// Setup expected values
String url = "foo";
boolean useWebView = false;
boolean enableJavaScript = false;
boolean enableDomStorage = false;
// Setup arguments map send on the method channel
Map<String, Object> args = new HashMap<>();
args.put("url", url);
args.put("useWebView", useWebView);
args.put("enableJavaScript", enableJavaScript);
args.put("enableDomStorage", enableDomStorage);
args.put("headers", new HashMap<>());
// Mock the launch method on the urlLauncher class
when(urlLauncher.launch(
eq(url), any(Bundle.class), eq(useWebView), eq(enableJavaScript), eq(enableDomStorage)))
.thenReturn(UrlLauncher.LaunchStatus.NO_ACTIVITY);
// Act by calling the "launch" method on the method channel
methodCallHandler = new MethodCallHandlerImpl(urlLauncher);
methodCallHandler.onMethodCall(new MethodCall("launch", args), result);
// Verify the results and assert
verify(result, times(1))
.error("NO_ACTIVITY", "Launching a URL requires a foreground activity.", null);
}
@Test
public void onMethodCall_launchReturnsActivityNotFoundError() {
// Setup mock objects
urlLauncher = mock(UrlLauncher.class);
Result result = mock(Result.class);
// Setup expected values
String url = "foo";
boolean useWebView = false;
boolean enableJavaScript = false;
boolean enableDomStorage = false;
// Setup arguments map send on the method channel
Map<String, Object> args = new HashMap<>();
args.put("url", url);
args.put("useWebView", useWebView);
args.put("enableJavaScript", enableJavaScript);
args.put("enableDomStorage", enableDomStorage);
args.put("headers", new HashMap<>());
// Mock the launch method on the urlLauncher class
when(urlLauncher.launch(
eq(url), any(Bundle.class), eq(useWebView), eq(enableJavaScript), eq(enableDomStorage)))
.thenReturn(UrlLauncher.LaunchStatus.ACTIVITY_NOT_FOUND);
// Act by calling the "launch" method on the method channel
methodCallHandler = new MethodCallHandlerImpl(urlLauncher);
methodCallHandler.onMethodCall(new MethodCall("launch", args), result);
// Verify the results and assert
verify(result, times(1))
.error(
"ACTIVITY_NOT_FOUND",
String.format("No Activity found to handle intent { %s }", url),
null);
}
@Test
public void onMethodCall_launchReturnsTrue() {
// Setup mock objects
urlLauncher = mock(UrlLauncher.class);
Result result = mock(Result.class);
// Setup expected values
String url = "foo";
boolean useWebView = false;
boolean enableJavaScript = false;
boolean enableDomStorage = false;
// Setup arguments map send on the method channel
Map<String, Object> args = new HashMap<>();
args.put("url", url);
args.put("useWebView", useWebView);
args.put("enableJavaScript", enableJavaScript);
args.put("enableDomStorage", enableDomStorage);
args.put("headers", new HashMap<>());
// Mock the launch method on the urlLauncher class
when(urlLauncher.launch(
eq(url), any(Bundle.class), eq(useWebView), eq(enableJavaScript), eq(enableDomStorage)))
.thenReturn(UrlLauncher.LaunchStatus.OK);
// Act by calling the "launch" method on the method channel
methodCallHandler = new MethodCallHandlerImpl(urlLauncher);
methodCallHandler.onMethodCall(new MethodCall("launch", args), result);
// Verify the results and assert
verify(result, times(1)).success(true);
}
@Test
public void onMethodCall_closeWebView() {
urlLauncher = mock(UrlLauncher.class);
methodCallHandler = new MethodCallHandlerImpl(urlLauncher);
String url = "foo";
when(urlLauncher.canLaunch(url)).thenReturn(true);
Result result = mock(Result.class);
Map<String, Object> args = new HashMap<>();
args.put("url", url);
methodCallHandler.onMethodCall(new MethodCall("closeWebView", args), result);
verify(urlLauncher, times(1)).closeWebView();
verify(result, times(1)).success(null);
}
}
{
"configVersion": 2,
"packages": [
{
"name": "_fe_analyzer_shared",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/_fe_analyzer_shared-14.0.0",
"packageUri": "lib/",
"languageVersion": "2.2"
},
{
"name": "analyzer",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/analyzer-0.41.2",
"packageUri": "lib/",
"languageVersion": "2.7"
},
{
"name": "archive",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/archive-2.0.13",
"packageUri": "lib/",
"languageVersion": "2.0"
},
{
"name": "args",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/args-1.6.0",
"packageUri": "lib/",
"languageVersion": "2.3"
},
{
"name": "async",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/async-2.5.0-nullsafety.1",
"packageUri": "lib/",
"languageVersion": "2.10"
},
{
"name": "boolean_selector",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/boolean_selector-2.1.0-nullsafety.1",
"packageUri": "lib/",
"languageVersion": "2.10"
},
{
"name": "build",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/build-1.6.2",
"packageUri": "lib/",
"languageVersion": "2.9"
},
{
"name": "built_collection",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/built_collection-4.3.2",
"packageUri": "lib/",
"languageVersion": "2.6"
},
{
"name": "built_value",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/built_value-7.1.0",
"packageUri": "lib/",
"languageVersion": "2.3"
},
{
"name": "characters",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/characters-1.1.0-nullsafety.3",
"packageUri": "lib/",
"languageVersion": "2.10"
},
{
"name": "charcode",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/charcode-1.2.0-nullsafety.1",
"packageUri": "lib/",
"languageVersion": "2.10"
},
{
"name": "cli_util",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/cli_util-0.2.0",
"packageUri": "lib/",
"languageVersion": "2.0"
},
{
"name": "clock",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/clock-1.1.0-nullsafety.1",
"packageUri": "lib/",
"languageVersion": "2.10"
},
{
"name": "code_builder",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/code_builder-3.7.0",
"packageUri": "lib/",
"languageVersion": "2.7"
},
{
"name": "collection",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/collection-1.15.0-nullsafety.3",
"packageUri": "lib/",
"languageVersion": "2.10"
},
{
"name": "convert",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/convert-2.1.1",
"packageUri": "lib/",
"languageVersion": "1.17"
},
{
"name": "crypto",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/crypto-2.1.5",
"packageUri": "lib/",
"languageVersion": "2.3"
},
{
"name": "dart_style",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/dart_style-1.3.12",
"packageUri": "lib/",
"languageVersion": "2.9"
},
{
"name": "fake_async",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/fake_async-1.2.0-nullsafety.1",
"packageUri": "lib/",
"languageVersion": "2.10"
},
{
"name": "file",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/file-6.0.0-nullsafety.2",
"packageUri": "lib/",
"languageVersion": "2.10"
},
{
"name": "fixnum",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/fixnum-0.10.11",
"packageUri": "lib/",
"languageVersion": "2.1"
},
{
"name": "flutter",
"rootUri": "file:///D:/dev/flutter/packages/flutter",
"packageUri": "lib/",
"languageVersion": "2.10"
},
{
"name": "flutter_driver",
"rootUri": "file:///D:/dev/flutter/packages/flutter_driver",
"packageUri": "lib/",
"languageVersion": "2.2"
},
{
"name": "flutter_test",
"rootUri": "file:///D:/dev/flutter/packages/flutter_test",
"packageUri": "lib/",
"languageVersion": "2.2"
},
{
"name": "flutter_web_plugins",
"rootUri": "file:///D:/dev/flutter/packages/flutter_web_plugins",
"packageUri": "lib/",
"languageVersion": "2.0"
},
{
"name": "fuchsia_remote_debug_protocol",
"rootUri": "file:///D:/dev/flutter/packages/fuchsia_remote_debug_protocol",
"packageUri": "lib/",
"languageVersion": "2.2"
},
{
"name": "glob",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/glob-1.2.0",
"packageUri": "lib/",
"languageVersion": "2.1"
},
{
"name": "js",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/js-0.6.2",
"packageUri": "lib/",
"languageVersion": "2.0"
},
{
"name": "json_rpc_2",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/json_rpc_2-2.2.2",
"packageUri": "lib/",
"languageVersion": "2.2"
},
{
"name": "logging",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/logging-0.11.4",
"packageUri": "lib/",
"languageVersion": "2.0"
},
{
"name": "matcher",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/matcher-0.12.10-nullsafety.1",
"packageUri": "lib/",
"languageVersion": "2.10"
},
{
"name": "meta",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/meta-1.3.0-nullsafety.3",
"packageUri": "lib/",
"languageVersion": "2.10"
},
{
"name": "mockito",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/mockito-4.1.4",
"packageUri": "lib/",
"languageVersion": "2.7"
},
{
"name": "node_interop",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/node_interop-1.2.1",
"packageUri": "lib/",
"languageVersion": "2.9"
},
{
"name": "node_io",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/node_io-1.1.1",
"packageUri": "lib/",
"languageVersion": "2.2"
},
{
"name": "package_config",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/package_config-1.9.3",
"packageUri": "lib/",
"languageVersion": "2.7"
},
{
"name": "path",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/path-1.8.0-nullsafety.1",
"packageUri": "lib/",
"languageVersion": "2.10"
},
{
"name": "pedantic",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/pedantic-1.9.2",
"packageUri": "lib/",
"languageVersion": "2.1"
},
{
"name": "platform",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/platform-3.0.0-nullsafety.2",
"packageUri": "lib/",
"languageVersion": "2.10"
},
{
"name": "plugin_platform_interface",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/plugin_platform_interface-1.0.3",
"packageUri": "lib/",
"languageVersion": "2.1"
},
{
"name": "process",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/process-4.0.0-nullsafety.2",
"packageUri": "lib/",
"languageVersion": "2.10"
},
{
"name": "pub_semver",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/pub_semver-1.4.4",
"packageUri": "lib/",
"languageVersion": "2.0"
},
{
"name": "quiver",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/quiver-2.1.5",
"packageUri": "lib/",
"languageVersion": "2.0"
},
{
"name": "sky_engine",
"rootUri": "file:///D:/dev/flutter/bin/cache/pkg/sky_engine",
"packageUri": "lib/",
"languageVersion": "1.11"
},
{
"name": "source_gen",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/source_gen-0.9.10+3",
"packageUri": "lib/",
"languageVersion": "2.10"
},
{
"name": "source_span",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/source_span-1.8.0-nullsafety.2",
"packageUri": "lib/",
"languageVersion": "2.10"
},
{
"name": "stack_trace",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/stack_trace-1.10.0-nullsafety.1",
"packageUri": "lib/",
"languageVersion": "2.10"
},
{
"name": "stream_channel",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/stream_channel-2.1.0-nullsafety.1",
"packageUri": "lib/",
"languageVersion": "2.10"
},
{
"name": "string_scanner",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/string_scanner-1.1.0-nullsafety.1",
"packageUri": "lib/",
"languageVersion": "2.10"
},
{
"name": "sync_http",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/sync_http-0.2.0",
"packageUri": "lib/",
"languageVersion": "2.0"
},
{
"name": "term_glyph",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/term_glyph-1.2.0-nullsafety.1",
"packageUri": "lib/",
"languageVersion": "2.10"
},
{
"name": "test_api",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/test_api-0.2.19-nullsafety.2",
"packageUri": "lib/",
"languageVersion": "2.10"
},
{
"name": "typed_data",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/typed_data-1.3.0-nullsafety.3",
"packageUri": "lib/",
"languageVersion": "2.10"
},
{
"name": "url_launcher",
"rootUri": "../../",
"packageUri": "lib/",
"languageVersion": "2.1"
},
{
"name": "url_launcher_linux",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_linux-0.0.1+4",
"packageUri": "lib/",
"languageVersion": "2.1"
},
{
"name": "url_launcher_macos",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_macos-0.0.1+9",
"packageUri": "lib/",
"languageVersion": "2.1"
},
{
"name": "url_launcher_platform_interface",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_platform_interface-1.0.9",
"packageUri": "lib/",
"languageVersion": "2.1"
},
{
"name": "url_launcher_web",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_web-0.1.5+3",
"packageUri": "lib/",
"languageVersion": "2.2"
},
{
"name": "url_launcher_windows",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_windows-0.0.1+3",
"packageUri": "lib/",
"languageVersion": "2.1"
},
{
"name": "vector_math",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/vector_math-2.1.0-nullsafety.3",
"packageUri": "lib/",
"languageVersion": "2.10"
},
{
"name": "vm_service_client",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/vm_service_client-0.2.6+2",
"packageUri": "lib/",
"languageVersion": "2.0"
},
{
"name": "watcher",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/watcher-0.9.7+15",
"packageUri": "lib/",
"languageVersion": "2.2"
},
{
"name": "web_socket_channel",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/web_socket_channel-1.1.0",
"packageUri": "lib/",
"languageVersion": "2.0"
},
{
"name": "webdriver",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/webdriver-2.1.2",
"packageUri": "lib/",
"languageVersion": "2.0"
},
{
"name": "yaml",
"rootUri": "file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/yaml-2.2.1",
"packageUri": "lib/",
"languageVersion": "2.4"
},
{
"name": "url_launcher_example",
"rootUri": "../",
"packageUri": "lib/",
"languageVersion": "2.1"
}
],
"generated": "2021-03-16T02:13:54.531466Z",
"generator": "pub",
"generatorVersion": "2.10.4"
}
# This is a generated file; do not edit or check into version control.
url_launcher_linux=C:\\Users\\qiaomeng\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\url_launcher_linux-0.0.1+4\\
url_launcher_macos=C:\\Users\\qiaomeng\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\url_launcher_macos-0.0.1+9\\
url_launcher_web=C:\\Users\\qiaomeng\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\url_launcher_web-0.1.5+3\\
url_launcher_windows=C:\\Users\\qiaomeng\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\url_launcher_windows-0.0.1+3\\
url_launcher=D:\\android_project\\url_launcher\\
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"url_launcher","path":"D:\\\\android_project\\\\url_launcher\\\\","dependencies":[]}],"android":[{"name":"url_launcher","path":"D:\\\\android_project\\\\url_launcher\\\\","dependencies":[]}],"macos":[{"name":"url_launcher_macos","path":"C:\\\\Users\\\\qiaomeng\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\url_launcher_macos-0.0.1+9\\\\","dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"C:\\\\Users\\\\qiaomeng\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\url_launcher_linux-0.0.1+4\\\\","dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"C:\\\\Users\\\\qiaomeng\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\url_launcher_windows-0.0.1+3\\\\","dependencies":[]}],"web":[{"name":"url_launcher_web","path":"C:\\\\Users\\\\qiaomeng\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\url_launcher_web-0.1.5+3\\\\","dependencies":[]}]},"dependencyGraph":[{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_web","url_launcher_linux","url_launcher_macos","url_launcher_windows"]}],"date_created":"2021-03-16 10:13:54.698722","version":"1.22.4"}
\ No newline at end of file
# Generated by pub on 2021-03-16 10:13:54.516432.
_fe_analyzer_shared:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/_fe_analyzer_shared-14.0.0/lib/
analyzer:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/analyzer-0.41.2/lib/
archive:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/archive-2.0.13/lib/
args:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/args-1.6.0/lib/
async:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/async-2.5.0-nullsafety.1/lib/
boolean_selector:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/boolean_selector-2.1.0-nullsafety.1/lib/
build:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/build-1.6.2/lib/
built_collection:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/built_collection-4.3.2/lib/
built_value:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/built_value-7.1.0/lib/
characters:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/characters-1.1.0-nullsafety.3/lib/
charcode:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/charcode-1.2.0-nullsafety.1/lib/
cli_util:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/cli_util-0.2.0/lib/
clock:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/clock-1.1.0-nullsafety.1/lib/
code_builder:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/code_builder-3.7.0/lib/
collection:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/collection-1.15.0-nullsafety.3/lib/
convert:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/convert-2.1.1/lib/
crypto:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/crypto-2.1.5/lib/
dart_style:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/dart_style-1.3.12/lib/
fake_async:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/fake_async-1.2.0-nullsafety.1/lib/
file:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/file-6.0.0-nullsafety.2/lib/
fixnum:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/fixnum-0.10.11/lib/
flutter:file:///D:/dev/flutter/packages/flutter/lib/
flutter_driver:file:///D:/dev/flutter/packages/flutter_driver/lib/
flutter_test:file:///D:/dev/flutter/packages/flutter_test/lib/
flutter_web_plugins:file:///D:/dev/flutter/packages/flutter_web_plugins/lib/
fuchsia_remote_debug_protocol:file:///D:/dev/flutter/packages/fuchsia_remote_debug_protocol/lib/
glob:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/glob-1.2.0/lib/
js:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/js-0.6.2/lib/
json_rpc_2:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/json_rpc_2-2.2.2/lib/
logging:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/logging-0.11.4/lib/
matcher:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/matcher-0.12.10-nullsafety.1/lib/
meta:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/meta-1.3.0-nullsafety.3/lib/
mockito:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/mockito-4.1.4/lib/
node_interop:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/node_interop-1.2.1/lib/
node_io:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/node_io-1.1.1/lib/
package_config:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/package_config-1.9.3/lib/
path:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/path-1.8.0-nullsafety.1/lib/
pedantic:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/pedantic-1.9.2/lib/
platform:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/platform-3.0.0-nullsafety.2/lib/
plugin_platform_interface:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/plugin_platform_interface-1.0.3/lib/
process:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/process-4.0.0-nullsafety.2/lib/
pub_semver:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/pub_semver-1.4.4/lib/
quiver:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/quiver-2.1.5/lib/
sky_engine:file:///D:/dev/flutter/bin/cache/pkg/sky_engine/lib/
source_gen:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/source_gen-0.9.10+3/lib/
source_span:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/source_span-1.8.0-nullsafety.2/lib/
stack_trace:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/stack_trace-1.10.0-nullsafety.1/lib/
stream_channel:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/stream_channel-2.1.0-nullsafety.1/lib/
string_scanner:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/string_scanner-1.1.0-nullsafety.1/lib/
sync_http:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/sync_http-0.2.0/lib/
term_glyph:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/term_glyph-1.2.0-nullsafety.1/lib/
test_api:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/test_api-0.2.19-nullsafety.2/lib/
typed_data:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/typed_data-1.3.0-nullsafety.3/lib/
url_launcher:../lib/
url_launcher_linux:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_linux-0.0.1+4/lib/
url_launcher_macos:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_macos-0.0.1+9/lib/
url_launcher_platform_interface:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_platform_interface-1.0.9/lib/
url_launcher_web:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_web-0.1.5+3/lib/
url_launcher_windows:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_windows-0.0.1+3/lib/
vector_math:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/vector_math-2.1.0-nullsafety.3/lib/
vm_service_client:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/vm_service_client-0.2.6+2/lib/
watcher:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/watcher-0.9.7+15/lib/
web_socket_channel:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/web_socket_channel-1.1.0/lib/
webdriver:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/webdriver-2.1.2/lib/
yaml:file:///C:/Users/qiaomeng/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/yaml-2.2.1/lib/
url_launcher_example:lib/
# url_launcher_example
Demonstrates how to use the url_launcher plugin.
## Getting Started
For help getting started with Flutter, view our online
[documentation](https://flutter.dev/).
#Tue Mar 16 10:12:34 CST 2021
gradle.version=5.1.1
# Default ignored files
/shelf/
/workspace.xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="1.8" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="PLATFORM" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="1.8 (2)" />
<option name="modules">
<set>
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_linux-0.0.1+4/android" />
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_macos-0.0.1+9/android" />
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_web-0.1.5+3/android" />
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_windows-0.0.1+3/android" />
<option value="$PROJECT_DIR$/../../android" />
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
<option name="useQualifiedModuleNames" value="true" />
</GradleProjectSettings>
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="maven3" />
<option name="name" value="maven3" />
<option name="url" value="https://mirrors.tuna.tsinghua.edu.cn/flutter/download.flutter.io" />
</remote-repository>
<remote-repository>
<option name="id" value="BintrayJCenter2" />
<option name="name" value="BintrayJCenter2" />
<option name="url" value="https://jcenter.bintray.com/" />
</remote-repository>
<remote-repository>
<option name="id" value="Google2" />
<option name="name" value="Google2" />
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
</remote-repository>
</component>
</project>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: ./../build/app/intermediates/flutter/debug/libs.jar">
<CLASSES>
<root url="jar://$PROJECT_DIR$/../build/app/intermediates/flutter/debug/libs.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: androidx.activity:activity:1.0.0@aar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/4de50886b54a45d98bd144547d690898/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/4de50886b54a45d98bd144547d690898/res" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/4de50886b54a45d98bd144547d690898/AndroidManifest.xml" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.activity/activity/1.0.0/28eb83e6a29ac3fbb87aa632cfa0e644a313f491/activity-1.0.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: androidx.annotation:annotation:1.1.0">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.annotation/annotation/1.1.0/e3a6fb2f40e3a3842e6b7472628ba4ce416ea4c8/annotation-1.1.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.annotation/annotation/1.1.0/408af38ec57369afe3fd6466e1c4bfdd5f15fc92/annotation-1.1.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.annotation/annotation/1.1.0/8b7bdc00eb4d998bfbc76767b098620990f2a805/annotation-1.1.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: androidx.arch.core:core-common:2.1.0">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.arch.core/core-common/2.1.0/b3152fc64428c9354344bd89848ecddc09b6f07e/core-common-2.1.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.arch.core/core-common/2.1.0/80ac2d7c8e6400ce2fbc663cd1a7e1cbef38c4b8/core-common-2.1.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: androidx.arch.core:core-runtime:2.0.0@aar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/8f9a0a2cc554cadd1f2f04087cac05fb/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/8f9a0a2cc554cadd1f2f04087cac05fb/res" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/8f9a0a2cc554cadd1f2f04087cac05fb/AndroidManifest.xml" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.arch.core/core-runtime/2.0.0/bc41b287c95bc50a3cd27cb1b7cfb301805ba7f1/core-runtime-2.0.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: androidx.collection:collection:1.1.0">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.collection/collection/1.1.0/1f27220b47669781457de0d600849a5de0e89909/collection-1.1.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.collection/collection/1.1.0/bae67b0019fbb38498198fcc2d0282a340b71c5b/collection-1.1.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: androidx.core:core:1.1.0@aar">
<ANNOTATIONS>
<root url="jar://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/60097d4f898b7ca10f95c8bc18f64a6f/annotations.zip!/" />
</ANNOTATIONS>
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/60097d4f898b7ca10f95c8bc18f64a6f/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/60097d4f898b7ca10f95c8bc18f64a6f/res" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/60097d4f898b7ca10f95c8bc18f64a6f/AndroidManifest.xml" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.core/core/1.1.0/4ae37fad1fe95b42aa47a720908df37ba5d3c85e/core-1.1.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: androidx.customview:customview:1.0.0@aar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/4db461d735f03e828a775300339215d3/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/4db461d735f03e828a775300339215d3/res" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/4db461d735f03e828a775300339215d3/AndroidManifest.xml" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.customview/customview/1.0.0/61f6a717d144dff3a6bda413d9abeeb2bca71581/customview-1.0.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: androidx.fragment:fragment:1.1.0@aar">
<ANNOTATIONS>
<root url="jar://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/46b115632576266be3ed16a8648b1b02/annotations.zip!/" />
</ANNOTATIONS>
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/46b115632576266be3ed16a8648b1b02/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/46b115632576266be3ed16a8648b1b02/res" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/46b115632576266be3ed16a8648b1b02/AndroidManifest.xml" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.fragment/fragment/1.1.0/b9ebb04df2cb0cad4419af3c658690bc82aa5706/fragment-1.1.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: androidx.lifecycle:lifecycle-common:2.2.0">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.lifecycle/lifecycle-common/2.2.0/4ef09a745007778eef83b92f8f23987a8ea59496/lifecycle-common-2.2.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.lifecycle/lifecycle-common/2.2.0/d38861c5e1656c5eb1890b1fa149510f38aa5d42/lifecycle-common-2.2.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: androidx.lifecycle:lifecycle-common-java8:2.2.0">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.lifecycle/lifecycle-common-java8/2.2.0/cd3478503da69b1a7e0319bd2d1389943db9b364/lifecycle-common-java8-2.2.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.lifecycle/lifecycle-common-java8/2.2.0/777ad8a2c39ec412a8c77a3923ceb536946acb29/lifecycle-common-java8-2.2.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: androidx.lifecycle:lifecycle-livedata:2.0.0@aar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/898998f9d0108858b7e12bcd765c6a76/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/898998f9d0108858b7e12bcd765c6a76/res" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/898998f9d0108858b7e12bcd765c6a76/AndroidManifest.xml" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.lifecycle/lifecycle-livedata/2.0.0/740ce61935bd789380c01178bd8ce402402ebd2f/lifecycle-livedata-2.0.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: androidx.lifecycle:lifecycle-livedata-core:2.0.0@aar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/29746787bad6451bbaa4a3ff44779546/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/29746787bad6451bbaa4a3ff44779546/res" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/29746787bad6451bbaa4a3ff44779546/AndroidManifest.xml" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.lifecycle/lifecycle-livedata-core/2.0.0/c158207594782b42f3a2e08a5a029eb3319e4404/lifecycle-livedata-core-2.0.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: androidx.lifecycle:lifecycle-runtime:2.2.0@aar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/43bcdada84e6bd7826860912db3310b6/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/43bcdada84e6bd7826860912db3310b6/res" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/43bcdada84e6bd7826860912db3310b6/AndroidManifest.xml" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.lifecycle/lifecycle-runtime/2.2.0/bac4e407cc35ca0fcd4c3c18d699fa632475b019/lifecycle-runtime-2.2.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: androidx.lifecycle:lifecycle-viewmodel:2.1.0@aar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/c6f281fa249a633fe41363d646a54e86/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/c6f281fa249a633fe41363d646a54e86/res" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/c6f281fa249a633fe41363d646a54e86/AndroidManifest.xml" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.lifecycle/lifecycle-viewmodel/2.1.0/bfd86b9887c2343516f82bed91acbab34a45841d/lifecycle-viewmodel-2.1.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: androidx.loader:loader:1.0.0@aar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/8be28c36cc59055013a3e7b1cf9b9611/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/8be28c36cc59055013a3e7b1cf9b9611/res" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/8be28c36cc59055013a3e7b1cf9b9611/AndroidManifest.xml" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.loader/loader/1.0.0/b9ef587f3e46c7fe5b00264989764e43ff45cada/loader-1.0.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: androidx.savedstate:savedstate:1.0.0@aar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/94bf9fd34921bdc9b817ad3cb0af8ac7/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/94bf9fd34921bdc9b817ad3cb0af8ac7/res" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/94bf9fd34921bdc9b817ad3cb0af8ac7/AndroidManifest.xml" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.savedstate/savedstate/1.0.0/e6daf87ed227a6f80bb8accb466755a5ee01a652/savedstate-1.0.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: androidx.test:core:1.0.0@aar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/66526cf3c877d8418ad3c7297e647e81/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/66526cf3c877d8418ad3c7297e647e81/res" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/66526cf3c877d8418ad3c7297e647e81/AndroidManifest.xml" />
</CLASSES>
<JAVADOC>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.test/core/1.0.0/fb3d5e80a838f741ea0f7c223c127efbc9fc4ada/core-1.0.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.test/core/1.0.0/6406894ea7a0bc3887f6ccf47bf58a56e9217cb6/core-1.0.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: androidx.test:monitor:1.1.0@aar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/d09c5250e479e7871c95014f731f656b/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/d09c5250e479e7871c95014f731f656b/res" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/d09c5250e479e7871c95014f731f656b/AndroidManifest.xml" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.test/monitor/1.1.0/d5021e13cb13f510b6d876a591a7eb9f33d52688/monitor-1.1.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: androidx.versionedparcelable:versionedparcelable:1.1.0@aar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/cf8b72ef40837c4a3c7fc808bad6b980/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/cf8b72ef40837c4a3c7fc808bad6b980/res" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/cf8b72ef40837c4a3c7fc808bad6b980/AndroidManifest.xml" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.versionedparcelable/versionedparcelable/1.1.0/d9085927216387af679d18b6f472bc0fc5c7cc81/versionedparcelable-1.1.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: androidx.viewpager:viewpager:1.0.0@aar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/c02f5e5e09cd384c115b82e009a25de2/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/c02f5e5e09cd384c115b82e009a25de2/res" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-2/files-2.1/c02f5e5e09cd384c115b82e009a25de2/AndroidManifest.xml" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.viewpager/viewpager/1.0.0/db045f92188b9d247d5f556866f8861ab68528f0/viewpager-1.0.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: io.flutter:arm64_v8a_debug:1.0.0-2c956a31c0a3d350827aee6c56bb63337c5b4e6e">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/io.flutter/arm64_v8a_debug/1.0.0-2c956a31c0a3d350827aee6c56bb63337c5b4e6e/caf4bb9beec91fb690037b6b81d58ec7f54cc3d3/arm64_v8a_debug-1.0.0-2c956a31c0a3d350827aee6c56bb63337c5b4e6e.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: io.flutter:armeabi_v7a_debug:1.0.0-2c956a31c0a3d350827aee6c56bb63337c5b4e6e">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/io.flutter/armeabi_v7a_debug/1.0.0-2c956a31c0a3d350827aee6c56bb63337c5b4e6e/627724bf9606793d930ab87b5496ea4703b07b40/armeabi_v7a_debug-1.0.0-2c956a31c0a3d350827aee6c56bb63337c5b4e6e.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: io.flutter:flutter_embedding_debug:1.0.0-2c956a31c0a3d350827aee6c56bb63337c5b4e6e">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/io.flutter/flutter_embedding_debug/1.0.0-2c956a31c0a3d350827aee6c56bb63337c5b4e6e/d766fe2feb740ead017d002eae7d82dd4f337a93/flutter_embedding_debug-1.0.0-2c956a31c0a3d350827aee6c56bb63337c5b4e6e.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/io.flutter/flutter_embedding_debug/1.0.0-2c956a31c0a3d350827aee6c56bb63337c5b4e6e/deb466af784895bc1a2f24da6b05aac8bb88f6b4/flutter_embedding_debug-1.0.0-2c956a31c0a3d350827aee6c56bb63337c5b4e6e-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: io.flutter:x86_64_debug:1.0.0-2c956a31c0a3d350827aee6c56bb63337c5b4e6e">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/io.flutter/x86_64_debug/1.0.0-2c956a31c0a3d350827aee6c56bb63337c5b4e6e/eb0cf19997744cadd524699414821a128b3e10bc/x86_64_debug-1.0.0-2c956a31c0a3d350827aee6c56bb63337c5b4e6e.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Gradle: io.flutter:x86_debug:1.0.0-2c956a31c0a3d350827aee6c56bb63337c5b4e6e">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/io.flutter/x86_debug/1.0.0-2c956a31c0a3d350827aee6c56bb63337c5b4e6e/9de6a21df971ba38e99d827ddaa4b269782308b1/x86_debug-1.0.0-2c956a31c0a3d350827aee6c56bb63337c5b4e6e.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/modules/android.iml" filepath="$PROJECT_DIR$/.idea/modules/android.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/app/android.app.iml" filepath="$PROJECT_DIR$/.idea/modules/app/android.app.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/1393079023/android.url_launcher.iml" filepath="$PROJECT_DIR$/.idea/modules/1393079023/android.url_launcher.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/-852728612/android.url_launcher_linux.iml" filepath="$PROJECT_DIR$/.idea/modules/-852728612/android.url_launcher_linux.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/2097020000/android.url_launcher_macos.iml" filepath="$PROJECT_DIR$/.idea/modules/2097020000/android.url_launcher_macos.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/-1246178432/android.url_launcher_web.iml" filepath="$PROJECT_DIR$/.idea/modules/-1246178432/android.url_launcher_web.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/-1845139542/android.url_launcher_windows.iml" filepath="$PROJECT_DIR$/.idea/modules/-1845139542/android.url_launcher_windows.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":url_launcher_web" external.linked.project.path="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_web-0.1.5+3/android" external.root.project.path="$MODULE_DIR$/../../.." external.system.id="GRADLE" external.system.module.group="android" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":url_launcher_web" />
<option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" />
<option name="LAST_KNOWN_AGP_VERSION" />
</configuration>
</facet>
<facet type="java-gradle" name="Java-Gradle">
<configuration>
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/../../../../build/url_launcher_web" />
<option name="BUILDABLE" value="false" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_web-0.1.5+3/android">
<excludeFolder url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_web-0.1.5+3/android/.gradle" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":url_launcher_windows" external.linked.project.path="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_windows-0.0.1+3/android" external.root.project.path="$MODULE_DIR$/../../.." external.system.id="GRADLE" external.system.module.group="android" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":url_launcher_windows" />
<option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" />
<option name="LAST_KNOWN_AGP_VERSION" />
</configuration>
</facet>
<facet type="java-gradle" name="Java-Gradle">
<configuration>
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/../../../../build/url_launcher_windows" />
<option name="BUILDABLE" value="false" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_windows-0.0.1+3/android">
<excludeFolder url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_windows-0.0.1+3/android/.gradle" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":url_launcher_linux" external.linked.project.path="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_linux-0.0.1+4/android" external.root.project.path="$MODULE_DIR$/../../.." external.system.id="GRADLE" external.system.module.group="android" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":url_launcher_linux" />
<option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" />
<option name="LAST_KNOWN_AGP_VERSION" />
</configuration>
</facet>
<facet type="java-gradle" name="Java-Gradle">
<configuration>
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/../../../../build/url_launcher_linux" />
<option name="BUILDABLE" value="false" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_linux-0.0.1+4/android">
<excludeFolder url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_linux-0.0.1+4/android/.gradle" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":url_launcher" external.linked.project.path="$MODULE_DIR$/../../../../../android" external.root.project.path="$MODULE_DIR$/../../.." external.system.id="GRADLE" external.system.module.group="io.flutter.plugins.urllauncher" external.system.module.version="1.0-SNAPSHOT" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":url_launcher" />
<option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" value="3.4.2" />
<option name="LAST_KNOWN_AGP_VERSION" value="3.4.2" />
</configuration>
</facet>
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="debug" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
<afterSyncTasks>
<task>generateDebugSources</task>
</afterSyncTasks>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/../../../../../android/src/main/res;file://$MODULE_DIR$/../../../../../android/src/debug/res;file://$MODULE_DIR$/../../../../build/url_launcher/generated/res/rs/debug;file://$MODULE_DIR$/../../../../build/url_launcher/generated/res/resValues/debug" />
<option name="TEST_RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/../../../../../android/src/androidTest/res;file://$MODULE_DIR$/../../../../../android/src/androidTestDebug/res;file://$MODULE_DIR$/../../../../build/url_launcher/generated/res/rs/androidTest/debug;file://$MODULE_DIR$/../../../../build/url_launcher/generated/res/resValues/androidTest/debug" />
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
<option name="PROJECT_TYPE" value="1" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7">
<output url="file://$MODULE_DIR$/../../../../build/url_launcher/intermediates/javac/debug/compileDebugJavaWithJavac/classes" />
<output-test url="file://$MODULE_DIR$/../../../../build/url_launcher/intermediates/javac/debugUnitTest/compileDebugUnitTestJavaWithJavac/classes" />
<exclude-output />
<content url="file://$MODULE_DIR$/../../../../../android">
<sourceFolder url="file://$MODULE_DIR$/../../../../../android/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../../../../android/src/test/java" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/../../../../../android/.gradle" />
</content>
<content url="file://$MODULE_DIR$/../../../../build/url_launcher/generated/aidl_source_output_dir/debug/compileDebugAidl/out" />
<content url="file://$MODULE_DIR$/../../../../build/url_launcher/generated/aidl_source_output_dir/debugAndroidTest/compileDebugAndroidTestAidl/out" />
<content url="file://$MODULE_DIR$/../../../../build/url_launcher/generated/renderscript_source_output_dir/debug/compileDebugRenderscript/out" />
<content url="file://$MODULE_DIR$/../../../../build/url_launcher/generated/renderscript_source_output_dir/debugAndroidTest/compileDebugAndroidTestRenderscript/out" />
<content url="file://$MODULE_DIR$/../../../../build/url_launcher/generated/res/resValues/androidTest/debug" />
<content url="file://$MODULE_DIR$/../../../../build/url_launcher/generated/res/resValues/debug" />
<content url="file://$MODULE_DIR$/../../../../build/url_launcher/generated/res/rs/androidTest/debug" />
<content url="file://$MODULE_DIR$/../../../../build/url_launcher/generated/res/rs/debug" />
<content url="file://$MODULE_DIR$/../../../../build/url_launcher/generated/source/apt/androidTest/debug" />
<content url="file://$MODULE_DIR$/../../../../build/url_launcher/generated/source/apt/debug" />
<content url="file://$MODULE_DIR$/../../../../build/url_launcher/generated/source/apt/test/debug" />
<content url="file://$MODULE_DIR$/../../../../build/url_launcher/generated/source/buildConfig/androidTest/debug" />
<content url="file://$MODULE_DIR$/../../../../build/url_launcher/generated/source/buildConfig/debug" />
<orderEntry type="jdk" jdkName="Android API 29 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Gradle: io.flutter:flutter_embedding_debug:1.0.0-2c956a31c0a3d350827aee6c56bb63337c5b4e6e" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-common-java8:2.2.0" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-common:2.2.0" level="project" />
<orderEntry type="library" name="Gradle: androidx.arch.core:core-common:2.1.0" level="project" />
<orderEntry type="library" name="Gradle: androidx.collection:collection:1.1.0" level="project" />
<orderEntry type="library" name="Gradle: androidx.annotation:annotation:1.1.0" level="project" />
<orderEntry type="library" name="Gradle: androidx.fragment:fragment:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.activity:activity:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.viewpager:viewpager:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.loader:loader:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.customview:customview:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.core:core:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-runtime:2.2.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.savedstate:savedstate:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata-core:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.arch.core:core-runtime:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.versionedparcelable:versionedparcelable:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-viewmodel:2.1.0@aar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: androidx.test:core:1.0.0@aar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: androidx.test:monitor:1.1.0@aar" level="project" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":url_launcher_macos" external.linked.project.path="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_macos-0.0.1+9/android" external.root.project.path="$MODULE_DIR$/../../.." external.system.id="GRADLE" external.system.module.group="android" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":url_launcher_macos" />
<option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" />
<option name="LAST_KNOWN_AGP_VERSION" />
</configuration>
</facet>
<facet type="java-gradle" name="Java-Gradle">
<configuration>
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/../../../../build/url_launcher_macos" />
<option name="BUILDABLE" value="false" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_macos-0.0.1+9/android">
<excludeFolder url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/url_launcher_macos-0.0.1+9/android/.gradle" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="android" external.linked.project.path="$MODULE_DIR$/../.." external.root.project.path="$MODULE_DIR$/../.." external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="java-gradle" name="Java-Gradle">
<configuration>
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/../../../build" />
<option name="BUILDABLE" value="false" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$/../..">
<excludeFolder url="file://$MODULE_DIR$/../../.gradle" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$/../../../app" external.root.project.path="$MODULE_DIR$/../../.." external.system.id="GRADLE" external.system.module.group="android" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":app" />
<option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" value="3.4.2" />
<option name="LAST_KNOWN_AGP_VERSION" value="3.4.2" />
</configuration>
</facet>
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="debug" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
<afterSyncTasks>
<task>generateDebugSources</task>
</afterSyncTasks>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/../../../app/src/main/res;file://$MODULE_DIR$/../../../app/src/debug/res;file://$MODULE_DIR$/../../../../build/app/generated/res/rs/debug;file://$MODULE_DIR$/../../../../build/app/generated/res/resValues/debug" />
<option name="TEST_RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/../../../app/src/androidTest/res;file://$MODULE_DIR$/../../../app/src/androidTestDebug/res;file://$MODULE_DIR$/../../../../build/app/generated/res/rs/androidTest/debug;file://$MODULE_DIR$/../../../../build/app/generated/res/resValues/androidTest/debug" />
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/../../../../build/app/intermediates/javac/debug/compileDebugJavaWithJavac/classes" />
<output-test url="file://$MODULE_DIR$/../../../../build/app/intermediates/javac/debugUnitTest/compileDebugUnitTestJavaWithJavac/classes" />
<exclude-output />
<content url="file://$MODULE_DIR$/../../../app">
<sourceFolder url="file://$MODULE_DIR$/../../../app/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../../app/src/androidTestDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/../../../app/src/main/res" type="java-resource" />
<excludeFolder url="file://$MODULE_DIR$/../../../app/.gradle" />
</content>
<content url="file://$MODULE_DIR$/../../../../build/app/generated/aidl_source_output_dir/debug/compileDebugAidl/out" />
<content url="file://$MODULE_DIR$/../../../../build/app/generated/aidl_source_output_dir/debugAndroidTest/compileDebugAndroidTestAidl/out" />
<content url="file://$MODULE_DIR$/../../../../build/app/generated/renderscript_source_output_dir/debug/compileDebugRenderscript/out" />
<content url="file://$MODULE_DIR$/../../../../build/app/generated/renderscript_source_output_dir/debugAndroidTest/compileDebugAndroidTestRenderscript/out" />
<content url="file://$MODULE_DIR$/../../../../build/app/generated/res/resValues/androidTest/debug" />
<content url="file://$MODULE_DIR$/../../../../build/app/generated/res/resValues/debug" />
<content url="file://$MODULE_DIR$/../../../../build/app/generated/res/rs/androidTest/debug" />
<content url="file://$MODULE_DIR$/../../../../build/app/generated/res/rs/debug" />
<content url="file://$MODULE_DIR$/../../../../build/app/generated/source/apt/androidTest/debug" />
<content url="file://$MODULE_DIR$/../../../../build/app/generated/source/apt/debug" />
<content url="file://$MODULE_DIR$/../../../../build/app/generated/source/apt/test/debug" />
<content url="file://$MODULE_DIR$/../../../../build/app/generated/source/buildConfig/androidTest/debug" />
<content url="file://$MODULE_DIR$/../../../../build/app/generated/source/buildConfig/debug" />
<orderEntry type="jdk" jdkName="Android API 29 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Gradle: ./../build/app/intermediates/flutter/debug/libs.jar" level="project" />
<orderEntry type="library" name="Gradle: io.flutter:flutter_embedding_debug:1.0.0-2c956a31c0a3d350827aee6c56bb63337c5b4e6e" level="project" />
<orderEntry type="library" name="Gradle: io.flutter:armeabi_v7a_debug:1.0.0-2c956a31c0a3d350827aee6c56bb63337c5b4e6e" level="project" />
<orderEntry type="library" name="Gradle: io.flutter:arm64_v8a_debug:1.0.0-2c956a31c0a3d350827aee6c56bb63337c5b4e6e" level="project" />
<orderEntry type="library" name="Gradle: io.flutter:x86_64_debug:1.0.0-2c956a31c0a3d350827aee6c56bb63337c5b4e6e" level="project" />
<orderEntry type="library" name="Gradle: io.flutter:x86_debug:1.0.0-2c956a31c0a3d350827aee6c56bb63337c5b4e6e" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-common-java8:2.2.0" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-common:2.2.0" level="project" />
<orderEntry type="library" name="Gradle: androidx.arch.core:core-common:2.1.0" level="project" />
<orderEntry type="library" name="Gradle: androidx.collection:collection:1.1.0" level="project" />
<orderEntry type="library" name="Gradle: androidx.annotation:annotation:1.1.0" level="project" />
<orderEntry type="library" name="Gradle: androidx.fragment:fragment:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.activity:activity:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.viewpager:viewpager:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.loader:loader:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.customview:customview:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.core:core:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-runtime:2.2.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.savedstate:savedstate:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata-core:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.arch.core:core-runtime:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.versionedparcelable:versionedparcelable:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-viewmodel:2.1.0@aar" level="project" />
<orderEntry type="module" module-name="android.url_launcher" />
</component>
</module>
\ No newline at end of file
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 29
lintOptions {
disable 'InvalidPackage'
}
defaultConfig {
applicationId "io.flutter.plugins.urllauncherexample"
minSdkVersion 16
targetSdkVersion 28
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
}
flutter {
source '../..'
}
dependencies {
// testImplementation 'junit:junit:4.12'
// androidTestImplementation 'androidx.test:runner:1.2.0'
// androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
package io.flutter.plugins.urllauncherexample;
import androidx.test.rule.ActivityTestRule;
import dev.flutter.plugins.integration_test.FlutterTestRunner;
import org.junit.Rule;
import org.junit.runner.RunWith;
@RunWith(FlutterTestRunner.class)
@SuppressWarnings("deprecation")
public class EmbeddingV1ActivityTest {
@Rule
public ActivityTestRule<EmbeddingV1Activity> rule =
new ActivityTestRule<>(EmbeddingV1Activity.class);
}
package io.flutter.plugins.urllauncherexample;
import androidx.test.rule.ActivityTestRule;
import dev.flutter.plugins.integration_test.FlutterTestRunner;
import io.flutter.embedding.android.FlutterActivity;
import org.junit.Rule;
import org.junit.runner.RunWith;
@RunWith(FlutterTestRunner.class)
public class FlutterActivityTest {
@Rule
public ActivityTestRule<FlutterActivity> rule = new ActivityTestRule<>(FlutterActivity.class);
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.flutter.plugins.urllauncherexample">
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:icon="@mipmap/ic_launcher"
android:label="url_launcher_example"
android:name="io.flutter.app.FlutterApplication">
<activity
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection"
android:hardwareAccelerated="true"
android:exported="true"
android:name="io.flutter.plugins.urllauncherexample.EmbeddingV1Activity"
android:theme="@android:style/Theme.Black.NoTitleBar"
android:windowSoftInputMode="adjustResize">
</activity>
<activity
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection"
android:hardwareAccelerated="true"
android:name="io.flutter.embedding.android.FlutterActivity"
android:theme="@android:style/Theme.Black.NoTitleBar"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<meta-data android:name="flutterEmbedding" android:value="2"/>
</application>
<!-- The INTERNET permission is required for development. Specifically,
flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
package io.flutter.plugins;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import io.flutter.embedding.engine.FlutterEngine;
/**
* Generated file. Do not edit.
* This file is generated by the Flutter tool based on the
* plugins that support the Android platform.
*/
@Keep
public final class GeneratedPluginRegistrant {
public static void registerWith(@NonNull FlutterEngine flutterEngine) {
flutterEngine.getPlugins().add(new io.flutter.plugins.urllauncher.UrlLauncherPlugin());
}
}
// 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.urllauncherexample;
import android.os.Bundle;
import dev.flutter.plugins.integration_test.IntegrationTestPlugin;
import io.flutter.plugins.urllauncher.UrlLauncherPlugin;
@SuppressWarnings("deprecation")
public class EmbeddingV1Activity extends io.flutter.app.FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IntegrationTestPlugin.registerWith(
registrarFor("dev.flutter.plugins.integration_test.IntegrationTestPlugin"));
UrlLauncherPlugin.registerWith(
registrarFor("io.flutter.plugins.urllauncher.UrlLauncherPlugin"));
}
}
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.2'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
android.enableR8=true
#Wed Jul 31 20:16:04 BRT 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
sdk.dir=D:\\dev\\androidSdk
flutter.sdk=D:\\dev\\flutter
\ No newline at end of file
include ':app'
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
if (pluginsFile.exists()) {
pluginsFile.withInputStream { stream -> plugins.load(stream) }
}
plugins.each { name, path ->
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
include ":$name"
project(":$name").projectDir = pluginDirectory
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>MinimumOSVersion</key>
<string>8.0</string>
</dict>
</plist>
#include "Generated.xcconfig"
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
// This is a generated file; do not edit or check into version control.
FLUTTER_ROOT=D:\dev\flutter
FLUTTER_APPLICATION_PATH=D:\android_project\url_launcher\example
FLUTTER_TARGET=lib\main.dart
FLUTTER_BUILD_DIR=build
SYMROOT=${SOURCE_ROOT}/../build\ios
OTHER_LDFLAGS=$(inherited) -framework Flutter
FLUTTER_FRAMEWORK_DIR=D:\dev\flutter\bin\cache\artifacts\engine\ios
FLUTTER_BUILD_NAME=1.0.0
FLUTTER_BUILD_NUMBER=1
DART_OBFUSCATION=false
TRACK_WIDGET_CREATION=false
TREE_SHAKE_ICONS=false
PACKAGE_CONFIG=.packages
#include "Generated.xcconfig"
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#!/bin/sh
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=D:\dev\flutter"
export "FLUTTER_APPLICATION_PATH=D:\android_project\url_launcher\example"
export "FLUTTER_TARGET=lib\main.dart"
export "FLUTTER_BUILD_DIR=build"
export "SYMROOT=${SOURCE_ROOT}/../build\ios"
export "OTHER_LDFLAGS=$(inherited) -framework Flutter"
export "FLUTTER_FRAMEWORK_DIR=D:\dev\flutter\bin\cache\artifacts\engine\ios"
export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1"
export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=false"
export "TREE_SHAKE_ICONS=false"
export "PACKAGE_CONFIG=.packages"
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
2D92223F1EC1DA93007564B0 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D92223E1EC1DA93007564B0 /* GeneratedPluginRegistrant.m */; };
2E37D9A274B2EACB147AC51B /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 856D0913184F79C678A42603 /* libPods-Runner.a */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
2D92223D1EC1DA93007564B0 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GeneratedPluginRegistrant.h; path = Runner/GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
2D92223E1EC1DA93007564B0 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GeneratedPluginRegistrant.m; path = Runner/GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
836316F9AEA584411312E29F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
856D0913184F79C678A42603 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
A84BFEE343F54B983D1B67EB /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
2E37D9A274B2EACB147AC51B /* libPods-Runner.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
840012C8B5EDBCF56B0E4AC1 /* Pods */ = {
isa = PBXGroup;
children = (
836316F9AEA584411312E29F /* Pods-Runner.debug.xcconfig */,
A84BFEE343F54B983D1B67EB /* Pods-Runner.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
2D92223D1EC1DA93007564B0 /* GeneratedPluginRegistrant.h */,
2D92223E1EC1DA93007564B0 /* GeneratedPluginRegistrant.m */,
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
840012C8B5EDBCF56B0E4AC1 /* Pods */,
CF3B75C9A7D2FA2A4C99F110 /* Frameworks */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
97C146F11CF9000F007C117D /* Supporting Files */,
);
path = Runner;
sourceTree = "<group>";
};
97C146F11CF9000F007C117D /* Supporting Files */ = {
isa = PBXGroup;
children = (
97C146F21CF9000F007C117D /* main.m */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
CF3B75C9A7D2FA2A4C99F110 /* Frameworks */ = {
isa = PBXGroup;
children = (
856D0913184F79C678A42603 /* libPods-Runner.a */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
AB1344B0443C71CD721E1BB7 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1100;
ORGANIZATIONNAME = "The Chromium Authors";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
};
95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
AB1344B0443C71CD721E1BB7 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
97C146F31CF9000F007C117D /* main.m in Sources */,
2D92223F1EC1DA93007564B0 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.urlLauncher;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.urlLauncher;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1100"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>
// 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>
#import <UIKit/UIKit.h>
@interface AppDelegate : FlutterAppDelegate
@end
// 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.
#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
[super application:application didFinishLaunchingWithOptions:launchOptions];
return YES;
}
@end
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
//
// Generated file. Do not edit.
//
#ifndef GeneratedPluginRegistrant_h
#define GeneratedPluginRegistrant_h
#import <Flutter/Flutter.h>
NS_ASSUME_NONNULL_BEGIN
@interface GeneratedPluginRegistrant : NSObject
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry;
@end
NS_ASSUME_NONNULL_END
#endif /* GeneratedPluginRegistrant_h */
//
// Generated file. Do not edit.
//
#import "GeneratedPluginRegistrant.h"
#if __has_include(<url_launcher/FLTURLLauncherPlugin.h>)
#import <url_launcher/FLTURLLauncherPlugin.h>
#else
@import url_launcher;
#endif
@implementation GeneratedPluginRegistrant
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry {
[FLTURLLauncherPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTURLLauncherPlugin"]];
}
@end
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>url_launcher_example</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>
// 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>
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char* argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
// 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.
// ignore_for_file: public_member_api_docs
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'URL Launcher',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'URL Launcher'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Future<void> _launched;
String _phone = '';
Future<void> _launchInBrowser(String url) async {
if (await canLaunch(url)) {
await launch(
url,
forceSafariVC: false,
forceWebView: false,
headers: <String, String>{'my_header_key': 'my_header_value'},
);
} else {
throw 'Could not launch $url';
}
}
Future<void> _launchInWebViewOrVC(String url) async {
if (await canLaunch(url)) {
await launch(
url,
forceSafariVC: true,
forceWebView: true,
headers: <String, String>{'my_header_key': 'my_header_value'},
);
} else {
throw 'Could not launch $url';
}
}
Future<void> _launchInWebViewWithJavaScript(String url) async {
if (await canLaunch(url)) {
await launch(
url,
forceSafariVC: true,
forceWebView: true,
enableJavaScript: true,
);
} else {
throw 'Could not launch $url';
}
}
Future<void> _launchInWebViewWithDomStorage(String url) async {
if (await canLaunch(url)) {
await launch(
url,
forceSafariVC: true,
forceWebView: true,
enableDomStorage: true,
);
} else {
throw 'Could not launch $url';
}
}
Future<void> _launchUniversalLinkIos(String url) async {
if (await canLaunch(url)) {
final bool nativeAppLaunchSucceeded = await launch(
url,
forceSafariVC: false,
universalLinksOnly: true,
);
if (!nativeAppLaunchSucceeded) {
await launch(
url,
forceSafariVC: true,
);
}
}
}
Widget _launchStatus(BuildContext context, AsyncSnapshot<void> snapshot) {
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return const Text('');
}
}
Future<void> _makePhoneCall(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
@override
Widget build(BuildContext context) {
const String toLaunch = 'https://www.cylog.org/headers/';
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView(
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: TextField(
onChanged: (String text) => _phone = text,
decoration: const InputDecoration(
hintText: 'Input the phone number to launch')),
),
RaisedButton(
onPressed: () => setState(() {
_launched = _makePhoneCall('tel:$_phone');
}),
child: const Text('Make phone call'),
),
const Padding(
padding: EdgeInsets.all(16.0),
child: Text(toLaunch),
),
RaisedButton(
onPressed: () => setState(() {
_launched = _launchInBrowser(toLaunch);
}),
child: const Text('Launch in browser'),
),
const Padding(padding: EdgeInsets.all(16.0)),
RaisedButton(
onPressed: () => setState(() {
_launched = _launchInWebViewOrVC(toLaunch);
}),
child: const Text('Launch in app'),
),
RaisedButton(
onPressed: () => setState(() {
_launched = _launchInWebViewWithJavaScript(toLaunch);
}),
child: const Text('Launch in app(JavaScript ON)'),
),
RaisedButton(
onPressed: () => setState(() {
_launched = _launchInWebViewWithDomStorage(toLaunch);
}),
child: const Text('Launch in app(DOM storage ON)'),
),
const Padding(padding: EdgeInsets.all(16.0)),
RaisedButton(
onPressed: () => setState(() {
_launched = _launchUniversalLinkIos(toLaunch);
}),
child: const Text(
'Launch a universal link in a native app, fallback to Safari.(Youtube)'),
),
const Padding(padding: EdgeInsets.all(16.0)),
RaisedButton(
onPressed: () => setState(() {
_launched = _launchInWebViewOrVC(toLaunch);
Timer(const Duration(seconds: 5), () {
print('Closing WebView after 5 seconds...');
closeWebView();
});
}),
child: const Text('Launch in app + close after 5 seconds'),
),
const Padding(padding: EdgeInsets.all(16.0)),
FutureBuilder<void>(future: _launched, builder: _launchStatus),
],
),
],
),
);
}
}
cmake_minimum_required(VERSION 3.10)
project(runner LANGUAGES CXX)
set(BINARY_NAME "example")
cmake_policy(SET CMP0063 NEW)
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
# Configure build options.
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "Debug" CACHE
STRING "Flutter build mode" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Profile" "Release")
endif()
# Compilation settings that should be applied to most targets.
function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_features(${TARGET} PUBLIC cxx_std_14)
target_compile_options(${TARGET} PRIVATE -Wall -Werror)
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
endfunction()
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
# Flutter library and tool build rules.
add_subdirectory(${FLUTTER_MANAGED_DIR})
# System-level dependencies.
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
# Application build
add_executable(${BINARY_NAME}
"main.cc"
"my_application.cc"
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
)
apply_standard_settings(${BINARY_NAME})
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
add_dependencies(${BINARY_NAME} flutter_assemble)
# Generated plugin build rules, which manage building the plugins and adding
# them to the application.
include(flutter/generated_plugins.cmake)
# === Installation ===
# By default, "installing" just makes a relocatable bundle in the build
# directory.
set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
endif()
# Start with a clean build bundle directory every time.
install(CODE "
file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
" COMPONENT Runtime)
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
COMPONENT Runtime)
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
COMPONENT Runtime)
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
if(PLUGIN_BUNDLED_LIBRARIES)
install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
endif()
# Fully re-copy the assets directory on each build to avoid having stale files
# from a previous install.
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
install(CODE "
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
" COMPONENT Runtime)
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
# Install the AOT library on non-Debug builds only.
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
endif()
cmake_minimum_required(VERSION 3.10)
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
# Configuration provided via flutter tool.
include(${EPHEMERAL_DIR}/generated_config.cmake)
# TODO: Move the rest of this into files in ephemeral. See
# https://github.com/flutter/flutter/issues/57146.
# Serves the same purpose as list(TRANSFORM ... PREPEND ...),
# which isn't available in 3.10.
function(list_prepend LIST_NAME PREFIX)
set(NEW_LIST "")
foreach(element ${${LIST_NAME}})
list(APPEND NEW_LIST "${PREFIX}${element}")
endforeach(element)
set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
endfunction()
# === Flutter Library ===
# System-level dependencies.
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
# Published to parent scope for install step.
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
list(APPEND FLUTTER_LIBRARY_HEADERS
"fl_basic_message_channel.h"
"fl_binary_codec.h"
"fl_binary_messenger.h"
"fl_dart_project.h"
"fl_engine.h"
"fl_json_message_codec.h"
"fl_json_method_codec.h"
"fl_message_codec.h"
"fl_method_call.h"
"fl_method_channel.h"
"fl_method_codec.h"
"fl_method_response.h"
"fl_plugin_registrar.h"
"fl_plugin_registry.h"
"fl_standard_message_codec.h"
"fl_standard_method_codec.h"
"fl_string_codec.h"
"fl_value.h"
"fl_view.h"
"flutter_linux.h"
)
list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
add_library(flutter INTERFACE)
target_include_directories(flutter INTERFACE
"${EPHEMERAL_DIR}"
)
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
target_link_libraries(flutter INTERFACE
PkgConfig::GTK
PkgConfig::GLIB
PkgConfig::GIO
)
add_dependencies(flutter flutter_assemble)
# === Flutter tool backend ===
# _phony_ is a non-existent file to force this command to run every time,
# since currently there's no way to get a full input/output list from the
# flutter tool.
add_custom_command(
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
${CMAKE_CURRENT_BINARY_DIR}/_phony_
COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
linux-x64 ${CMAKE_BUILD_TYPE}
)
add_custom_target(flutter_assemble DEPENDS
"${FLUTTER_LIBRARY}"
${FLUTTER_LIBRARY_HEADERS}
)
//
// Generated file. Do not edit.
//
#include "generated_plugin_registrant.h"
#include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry,
"UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
}
//
// Generated file. Do not edit.
//
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
#include <flutter_linux/flutter_linux.h>
// Registers Flutter plugins.
void fl_register_plugins(FlPluginRegistry* registry);
#endif // GENERATED_PLUGIN_REGISTRANT_
#
# Generated file, do not edit.
#
list(APPEND FLUTTER_PLUGIN_LIST
url_launcher_linux
)
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)
#include "my_application.h"
int main(int argc, char** argv) {
g_autoptr(MyApplication) app = my_application_new();
return g_application_run(G_APPLICATION(app), argc, argv);
}
#include "my_application.h"
#include <flutter_linux/flutter_linux.h>
#include "flutter/generated_plugin_registrant.h"
struct _MyApplication {
GtkApplication parent_instance;
};
G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
// Implements GApplication::activate.
static void my_application_activate(GApplication* application) {
GtkWindow* window =
GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
gtk_widget_show(GTK_WIDGET(header_bar));
gtk_header_bar_set_title(header_bar, "example");
gtk_header_bar_set_show_close_button(header_bar, TRUE);
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
gtk_window_set_default_size(window, 1280, 720);
gtk_widget_show(GTK_WIDGET(window));
g_autoptr(FlDartProject) project = fl_dart_project_new();
FlView* view = fl_view_new(project);
gtk_widget_show(GTK_WIDGET(view));
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
fl_register_plugins(FL_PLUGIN_REGISTRY(view));
gtk_widget_grab_focus(GTK_WIDGET(view));
}
static void my_application_class_init(MyApplicationClass* klass) {
G_APPLICATION_CLASS(klass)->activate = my_application_activate;
}
static void my_application_init(MyApplication* self) {}
MyApplication* my_application_new() {
return MY_APPLICATION(g_object_new(my_application_get_type(), nullptr));
}
#ifndef FLUTTER_MY_APPLICATION_H_
#define FLUTTER_MY_APPLICATION_H_
#include <gtk/gtk.h>
G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
GtkApplication)
/**
* my_application_new:
*
* Creates a new Flutter-based application.
*
* Returns: a new #MyApplication.
*/
MyApplication* my_application_new();
#endif // FLUTTER_MY_APPLICATION_H_
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"
//
// Generated file. Do not edit.
//
import FlutterMacOS
import Foundation
import url_launcher_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
}
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 51;
objects = {
/* Begin PBXAggregateTarget section */
33CC111A2044C6BA0003C045 /* Flutter Assemble */ = {
isa = PBXAggregateTarget;
buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */;
buildPhases = (
33CC111E2044C6BF0003C045 /* ShellScript */,
);
dependencies = (
);
name = "Flutter Assemble";
productName = FLX;
};
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };
33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
33D1A10422148B71006C7A3E /* FlutterMacOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */; };
33D1A10522148B93006C7A3E /* FlutterMacOS.framework in Bundle Framework */ = {isa = PBXBuildFile; fileRef = 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
D73912F022F37F9E000D13A0 /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D73912EF22F37F9E000D13A0 /* App.framework */; };
D73912F222F3801D000D13A0 /* App.framework in Bundle Framework */ = {isa = PBXBuildFile; fileRef = D73912EF22F37F9E000D13A0 /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
DD4A1B9DEDBB72C87CD7AE27 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5067D74CB28D28AE3B3DD05B /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 33CC10E52044A3C60003C045 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 33CC111A2044C6BA0003C045;
remoteInfo = FLX;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
33CC110E2044A8840003C045 /* Bundle Framework */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
D73912F222F3801D000D13A0 /* App.framework in Bundle Framework */,
33D1A10522148B93006C7A3E /* FlutterMacOS.framework in Bundle Framework */,
);
name = "Bundle Framework";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
33CC10ED2044A3C60003C045 /* url_launcher_example_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = url_launcher_example_example.app; sourceTree = BUILT_PRODUCTS_DIR; };
33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = "<group>"; };
33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = "<group>"; };
33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = "<group>"; };
33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = "<group>"; };
33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = "<group>"; };
33D1A10322148B71006C7A3E /* FlutterMacOS.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FlutterMacOS.framework; path = Flutter/ephemeral/FlutterMacOS.framework; sourceTree = SOURCE_ROOT; };
33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
5067D74CB28D28AE3B3DD05B /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
53F020549CA1E801ACA3428F /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
899489AD6AA35AECA4E2BEA6 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
B36FDC1D769C9045B8821207 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
D73912EF22F37F9E000D13A0 /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/ephemeral/App.framework; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
33CC10EA2044A3C60003C045 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D73912F022F37F9E000D13A0 /* App.framework in Frameworks */,
33D1A10422148B71006C7A3E /* FlutterMacOS.framework in Frameworks */,
DD4A1B9DEDBB72C87CD7AE27 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
33BA886A226E78AF003329D5 /* Configs */ = {
isa = PBXGroup;
children = (
33E5194F232828860026EE4D /* AppInfo.xcconfig */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
333000ED22D3DE5D00554162 /* Warnings.xcconfig */,
);
path = Configs;
sourceTree = "<group>";
};
33CC10E42044A3C60003C045 = {
isa = PBXGroup;
children = (
33FAB671232836740065AC1E /* Runner */,
33CEB47122A05771004F2AC0 /* Flutter */,
33CC10EE2044A3C60003C045 /* Products */,
D73912EC22F37F3D000D13A0 /* Frameworks */,
96C1F6D923BD5787E8EBE8FC /* Pods */,
);
sourceTree = "<group>";
};
33CC10EE2044A3C60003C045 /* Products */ = {
isa = PBXGroup;
children = (
33CC10ED2044A3C60003C045 /* url_launcher_example_example.app */,
);
name = Products;
sourceTree = "<group>";
};
33CC11242044D66E0003C045 /* Resources */ = {
isa = PBXGroup;
children = (
33CC10F22044A3C60003C045 /* Assets.xcassets */,
33CC10F42044A3C60003C045 /* MainMenu.xib */,
33CC10F72044A3C60003C045 /* Info.plist */,
);
name = Resources;
path = ..;
sourceTree = "<group>";
};
33CEB47122A05771004F2AC0 /* Flutter */ = {
isa = PBXGroup;
children = (
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */,
33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */,
33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */,
33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */,
D73912EF22F37F9E000D13A0 /* App.framework */,
33D1A10322148B71006C7A3E /* FlutterMacOS.framework */,
);
path = Flutter;
sourceTree = "<group>";
};
33FAB671232836740065AC1E /* Runner */ = {
isa = PBXGroup;
children = (
33CC10F02044A3C60003C045 /* AppDelegate.swift */,
33CC11122044BFA00003C045 /* MainFlutterWindow.swift */,
33E51913231747F40026EE4D /* DebugProfile.entitlements */,
33E51914231749380026EE4D /* Release.entitlements */,
33CC11242044D66E0003C045 /* Resources */,
33BA886A226E78AF003329D5 /* Configs */,
);
path = Runner;
sourceTree = "<group>";
};
96C1F6D923BD5787E8EBE8FC /* Pods */ = {
isa = PBXGroup;
children = (
899489AD6AA35AECA4E2BEA6 /* Pods-Runner.debug.xcconfig */,
B36FDC1D769C9045B8821207 /* Pods-Runner.release.xcconfig */,
53F020549CA1E801ACA3428F /* Pods-Runner.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
D73912EC22F37F3D000D13A0 /* Frameworks */ = {
isa = PBXGroup;
children = (
5067D74CB28D28AE3B3DD05B /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
33CC10EC2044A3C60003C045 /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
C318D59394D0E38099411848 /* [CP] Check Pods Manifest.lock */,
33CC10E92044A3C60003C045 /* Sources */,
33CC10EA2044A3C60003C045 /* Frameworks */,
33CC10EB2044A3C60003C045 /* Resources */,
33CC110E2044A8840003C045 /* Bundle Framework */,
3399D490228B24CF009A79C7 /* ShellScript */,
50C74DCD840D9B569BE3D48F /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
33CC11202044C79F0003C045 /* PBXTargetDependency */,
);
name = Runner;
productName = Runner;
productReference = 33CC10ED2044A3C60003C045 /* url_launcher_example_example.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
33CC10E52044A3C60003C045 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 0930;
ORGANIZATIONNAME = "The Flutter Authors";
TargetAttributes = {
33CC10EC2044A3C60003C045 = {
CreatedOnToolsVersion = 9.2;
LastSwiftMigration = 1100;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.Sandbox = {
enabled = 1;
};
};
};
33CC111A2044C6BA0003C045 = {
CreatedOnToolsVersion = 9.2;
ProvisioningStyle = Manual;
};
};
};
buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 8.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 33CC10E42044A3C60003C045;
productRefGroup = 33CC10EE2044A3C60003C045 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
33CC10EC2044A3C60003C045 /* Runner */,
33CC111A2044C6BA0003C045 /* Flutter Assemble */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
33CC10EB2044A3C60003C045 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */,
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3399D490228B24CF009A79C7 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename\n";
};
33CC111E2044C6BF0003C045 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
Flutter/ephemeral/FlutterInputs.xcfilelist,
);
inputPaths = (
Flutter/ephemeral/tripwire,
);
outputFileListPaths = (
Flutter/ephemeral/FlutterOutputs.xcfilelist,
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh\ntouch Flutter/ephemeral/tripwire\n";
};
50C74DCD840D9B569BE3D48F /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
C318D59394D0E38099411848 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
33CC10E92044A3C60003C045 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */,
33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */,
335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
33CC11202044C79F0003C045 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */;
targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
33CC10F42044A3C60003C045 /* MainMenu.xib */ = {
isa = PBXVariantGroup;
children = (
33CC10F52044A3C60003C045 /* Base */,
);
name = MainMenu.xib;
path = Runner;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
338D0CE9231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Profile;
};
338D0CEA231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter/ephemeral",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
};
name = Profile;
};
338D0CEB231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Manual;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Profile;
};
33CC10F92044A3C60003C045 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
33CC10FA2044A3C60003C045 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Release;
};
33CC10FC2044A3C60003C045 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter/ephemeral",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
33CC10FD2044A3C60003C045 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter/ephemeral",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
};
name = Release;
};
33CC111C2044C6BA0003C045 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Manual;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
33CC111D2044C6BA0003C045 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC10F92044A3C60003C045 /* Debug */,
33CC10FA2044A3C60003C045 /* Release */,
338D0CE9231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC10FC2044A3C60003C045 /* Debug */,
33CC10FD2044A3C60003C045 /* Release */,
338D0CEA231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC111C2044C6BA0003C045 /* Debug */,
33CC111D2044C6BA0003C045 /* Release */,
338D0CEB231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 33CC10E52044A3C60003C045 /* Project object */;
}
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1000"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "url_launcher_example_example.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "00380F9121DF178D00097171"
BuildableName = "RunnerUITests.xctest"
BlueprintName = "RunnerUITests"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "url_launcher_example_example.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "url_launcher_example_example.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "url_launcher_example_example.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
import Cocoa
import FlutterMacOS
@NSApplicationMain
class AppDelegate: FlutterAppDelegate {
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}
}
{
"images" : [
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "app_icon_16.png",
"scale" : "1x"
},
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "app_icon_32.png",
"scale" : "2x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "app_icon_32.png",
"scale" : "1x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "app_icon_64.png",
"scale" : "2x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "app_icon_128.png",
"scale" : "1x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "app_icon_256.png",
"scale" : "2x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "app_icon_256.png",
"scale" : "1x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "app_icon_512.png",
"scale" : "2x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "app_icon_512.png",
"scale" : "1x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "app_icon_1024.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Runner" customModuleProvider="target">
<connections>
<outlet property="applicationMenu" destination="uQy-DD-JDr" id="XBo-yE-nKs"/>
<outlet property="mainFlutterWindow" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
</connections>
</customObject>
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items>
<menuItem title="APP_NAME" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="APP_NAME" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="About APP_NAME" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
<menuItem title="Services" id="NMo-om-nkz">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
<menuItem title="Hide APP_NAME" keyEquivalent="h" id="Olw-nP-bQN">
<connections>
<action selector="hide:" target="-1" id="PnN-Uc-m68"/>
</connections>
</menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
</connections>
</menuItem>
<menuItem title="Show All" id="Kd2-mp-pUS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit APP_NAME" keyEquivalent="q" id="4sb-4s-VLi">
<connections>
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Edit" id="5QF-Oa-p0T">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
<items>
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
<connections>
<action selector="undo:" target="-1" id="M6e-cu-g7V"/>
</connections>
</menuItem>
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
<connections>
<action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
<connections>
<action selector="cut:" target="-1" id="YJe-68-I9s"/>
</connections>
</menuItem>
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
<connections>
<action selector="copy:" target="-1" id="G1f-GL-Joy"/>
</connections>
</menuItem>
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
<connections>
<action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
</connections>
</menuItem>
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
</connections>
</menuItem>
<menuItem title="Delete" id="pa3-QI-u2k">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
</connections>
</menuItem>
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
<connections>
<action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
<menuItem title="Find" id="4EN-yA-p0u">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Find" id="1b7-l0-nxx">
<items>
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
<connections>
<action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
</connections>
</menuItem>
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
</connections>
</menuItem>
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
<connections>
<action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
</connections>
</menuItem>
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
<connections>
<action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
</connections>
</menuItem>
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
<connections>
<action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
</connections>
</menuItem>
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
<connections>
<action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
<items>
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
<connections>
<action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
</connections>
</menuItem>
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
<connections>
<action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
</connections>
</menuItem>
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
</connections>
</menuItem>
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Substitutions" id="9ic-FL-obx">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
<items>
<menuItem title="Show Substitutions" id="z6F-FW-3nz">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
</connections>
</menuItem>
<menuItem title="Smart Quotes" id="hQb-2v-fYv">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
</connections>
</menuItem>
<menuItem title="Smart Dashes" id="rgM-f4-ycn">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
</connections>
</menuItem>
<menuItem title="Smart Links" id="cwL-P1-jid">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
</connections>
</menuItem>
<menuItem title="Data Detectors" id="tRr-pd-1PS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
</connections>
</menuItem>
<menuItem title="Text Replacement" id="HFQ-gK-NFA">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Transformations" id="2oI-Rn-ZJC">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Transformations" id="c8a-y6-VQd">
<items>
<menuItem title="Make Upper Case" id="vmV-6d-7jI">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
</connections>
</menuItem>
<menuItem title="Make Lower Case" id="d9M-CD-aMd">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
</connections>
</menuItem>
<menuItem title="Capitalize" id="UEZ-Bs-lqG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Speech" id="xrE-MZ-jX0">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Speech" id="3rS-ZA-NoH">
<items>
<menuItem title="Start Speaking" id="Ynk-f8-cLZ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
</connections>
</menuItem>
<menuItem title="Stop Speaking" id="Oyz-dy-DGm">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="View" id="H8h-7b-M4v">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="View" id="HyV-fh-RgO">
<items>
<menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="toggleFullScreen:" target="-1" id="dU3-MA-1Rq"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="aUF-d1-5bR">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
<connections>
<action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
</connections>
</menuItem>
<menuItem title="Zoom" id="R4o-n2-Eq4">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
<point key="canvasLocation" x="142" y="-258"/>
</menu>
<window title="APP_NAME" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="MainFlutterWindow" customModule="Runner" customModuleProvider="target">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<rect key="contentRect" x="335" y="390" width="800" height="600"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1577"/>
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="800" height="600"/>
<autoresizingMask key="autoresizingMask"/>
</view>
</window>
</objects>
</document>
// Application-level settings for the Runner target.
//
// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the
// future. If not, the values below would default to using the project name when this becomes a
// 'flutter create' template.
// The application's name. By default this is also the title of the Flutter window.
PRODUCT_NAME = url_launcher_example_example
// The application's bundle identifier
PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.urlLauncherExample
// The copyright displayed in application information
PRODUCT_COPYRIGHT = Copyright © 2019 io.flutter.plugins. All rights reserved.
#include "../../Flutter/Flutter-Debug.xcconfig"
#include "Warnings.xcconfig"
#include "../../Flutter/Flutter-Release.xcconfig"
#include "Warnings.xcconfig"
WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings
GCC_WARN_UNDECLARED_SELECTOR = YES
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
CLANG_WARN_PRAGMA_PACK = YES
CLANG_WARN_STRICT_PROTOTYPES = YES
CLANG_WARN_COMMA = YES
GCC_WARN_STRICT_SELECTOR_MATCH = YES
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
GCC_WARN_SHADOW = YES
CLANG_WARN_UNREACHABLE_CODE = YES
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>$(PRODUCT_COPYRIGHT)</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>
import Cocoa
import FlutterMacOS
class MainFlutterWindow: NSWindow {
override func awakeFromNib() {
let flutterViewController = FlutterViewController.init()
let windowFrame = self.frame
self.contentViewController = flutterViewController
self.setFrame(windowFrame, display: true)
RegisterGeneratedPlugins(registry: flutterViewController)
super.awakeFromNib()
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
</dict>
</plist>
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_fe_analyzer_shared:
dependency: transitive
description:
name: _fe_analyzer_shared
url: "https://pub.flutter-io.cn"
source: hosted
version: "14.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.41.2"
archive:
dependency: transitive
description:
name: archive
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.13"
args:
dependency: transitive
description:
name: args
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.6.0"
async:
dependency: transitive
description:
name: async
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.5.0-nullsafety.1"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.0-nullsafety.1"
build:
dependency: transitive
description:
name: build
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.6.2"
built_collection:
dependency: transitive
description:
name: built_collection
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.3.2"
built_value:
dependency: transitive
description:
name: built_value
url: "https://pub.flutter-io.cn"
source: hosted
version: "7.1.0"
characters:
dependency: transitive
description:
name: characters
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.0-nullsafety.3"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.0-nullsafety.1"
cli_util:
dependency: transitive
description:
name: cli_util
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.2.0"
clock:
dependency: transitive
description:
name: clock
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.0-nullsafety.1"
code_builder:
dependency: transitive
description:
name: code_builder
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.7.0"
collection:
dependency: transitive
description:
name: collection
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.15.0-nullsafety.3"
convert:
dependency: transitive
description:
name: convert
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.1"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.5"
dart_style:
dependency: transitive
description:
name: dart_style
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.3.12"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.0-nullsafety.1"
file:
dependency: transitive
description:
name: file
url: "https://pub.flutter-io.cn"
source: hosted
version: "6.0.0-nullsafety.2"
fixnum:
dependency: transitive
description:
name: fixnum
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.10.11"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_driver:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
flutter_test:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
fuchsia_remote_debug_protocol:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
glob:
dependency: transitive
description:
name: glob
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.0"
js:
dependency: transitive
description:
name: js
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.6.2"
json_rpc_2:
dependency: transitive
description:
name: json_rpc_2
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.2.2"
logging:
dependency: transitive
description:
name: logging
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.11.4"
matcher:
dependency: transitive
description:
name: matcher
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.12.10-nullsafety.1"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.3.0-nullsafety.3"
mockito:
dependency: "direct dev"
description:
name: mockito
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.1.4"
node_interop:
dependency: transitive
description:
name: node_interop
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.1"
node_io:
dependency: transitive
description:
name: node_io
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.1"
package_config:
dependency: transitive
description:
name: package_config
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.9.3"
path:
dependency: transitive
description:
name: path
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.8.0-nullsafety.1"
pedantic:
dependency: "direct dev"
description:
name: pedantic
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.9.2"
platform:
dependency: transitive
description:
name: platform
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.0-nullsafety.2"
plugin_platform_interface:
dependency: "direct dev"
description:
name: plugin_platform_interface
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.3"
process:
dependency: transitive
description:
name: process
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.0.0-nullsafety.2"
pub_semver:
dependency: transitive
description:
name: pub_semver
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.4.4"
quiver:
dependency: transitive
description:
name: quiver
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.5"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
source_gen:
dependency: transitive
description:
name: source_gen
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.9.10+3"
source_span:
dependency: transitive
description:
name: source_span
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.8.0-nullsafety.2"
stack_trace:
dependency: transitive
description:
name: stack_trace
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.10.0-nullsafety.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.0-nullsafety.1"
string_scanner:
dependency: transitive
description:
name: string_scanner
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.0-nullsafety.1"
sync_http:
dependency: transitive
description:
name: sync_http
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.2.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.0-nullsafety.1"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.2.19-nullsafety.2"
typed_data:
dependency: transitive
description:
name: typed_data
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.3.0-nullsafety.3"
url_launcher:
dependency: "direct main"
description:
path: ".."
relative: true
source: path
version: "5.7.10"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.0.1+4"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.0.1+9"
url_launcher_platform_interface:
dependency: transitive
description:
name: url_launcher_platform_interface
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.9"
url_launcher_web:
dependency: transitive
description:
name: url_launcher_web
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.1.5+3"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.0.1+3"
vector_math:
dependency: transitive
description:
name: vector_math
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.0-nullsafety.3"
vm_service_client:
dependency: transitive
description:
name: vm_service_client
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.2.6+2"
watcher:
dependency: transitive
description:
name: watcher
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.9.7+15"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.0"
webdriver:
dependency: transitive
description:
name: webdriver
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.2"
yaml:
dependency: transitive
description:
name: yaml
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.2.1"
sdks:
dart: ">=2.10.0 <2.11.0"
flutter: ">=1.22.0 <2.0.0"
name: url_launcher_example
description: Demonstrates how to use the url_launcher plugin.
dependencies:
flutter:
sdk: flutter
url_launcher:
path: ../
dev_dependencies:
flutter_driver:
sdk: flutter
pedantic: ^1.8.0
mockito: ^4.1.1
plugin_platform_interface: ^1.0.0
flutter:
uses-material-design: true
environment:
sdk: ">=2.1.0 <3.0.0"
flutter: ">=1.12.13+hotfix.5 <2.0.0"
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart';
import 'package:mockito/mockito.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart';
import 'package:url_launcher_example/main.dart';
void main() {
final MockUrlLauncher mock = MockUrlLauncher();
UrlLauncherPlatform.instance = mock;
testWidgets('Can open URLs', (WidgetTester tester) async {
await tester.pumpWidget(MyApp());
const String defaultUrl = 'https://www.cylog.org/headers/';
when(mock.canLaunch(defaultUrl)).thenAnswer((_) => Future.value(true));
const Map<String, String> defaultHeaders = {
'my_header_key': 'my_header_value'
};
verifyNever(mock.launch(defaultUrl,
useSafariVC: false,
useWebView: false,
enableDomStorage: false,
enableJavaScript: false,
universalLinksOnly: false,
headers: defaultHeaders));
Finder browserlaunchBtn =
find.widgetWithText(RaisedButton, 'Launch in browser');
expect(browserlaunchBtn, findsOneWidget);
await tester.tap(browserlaunchBtn);
verify(mock.launch(defaultUrl,
useSafariVC: false,
useWebView: false,
enableDomStorage: false,
enableJavaScript: false,
universalLinksOnly: false,
headers: defaultHeaders))
.called(1);
});
}
class MockUrlLauncher extends Mock
with MockPlatformInterfaceMixin
implements UrlLauncherPlatform {}
// Copyright 2019, the Chromium project authors. Please see the AUTHORS file
// for details. 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 'dart:convert';
import 'dart:io';
import 'package:flutter_driver/flutter_driver.dart';
Future<void> main() async {
final FlutterDriver driver = await FlutterDriver.connect();
final String data =
await driver.requestData(null, timeout: const Duration(minutes: 1));
await driver.close();
final Map<String, dynamic> result = jsonDecode(data);
exit(result['result'] == 'true' ? 0 : 1);
}
<?xml version="1.0" encoding="UTF-8"?>
<module type="FLUTTER_MODULE_TYPE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.idea" />
<excludeFolder url="file://$MODULE_DIR$/.pub" />
<excludeFolder url="file://$MODULE_DIR$/build" />
<excludeFolder url="file://$MODULE_DIR$/packages" />
</content>
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Dart SDK" level="project" />
<orderEntry type="library" name="Dart SDK" level="application" />
<orderEntry type="library" name="Dart Packages" level="project" />
</component>
</module>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="An example of the url_launcher on the web.">
<!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="example">
<link rel="apple-touch-icon" href="icons/Icon-192.png">
<!-- Favicon -->
<link rel="shortcut icon" type="image/png" href="favicon.png"/>
<title>url_launcher web example</title>
<link rel="manifest" href="manifest.json">
</head>
<body>
<!-- This script installs service_worker.js to provide PWA functionality to
application. For more information, see:
https://developers.google.com/web/fundamentals/primers/service-workers -->
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
navigator.serviceWorker.register('flutter_service_worker.js');
});
}
</script>
<script src="main.dart.js" type="application/javascript"></script>
</body>
</html>
{
"name": "url_launcher example",
"short_name": "url_launcher",
"start_url": ".",
"display": "minimal-ui",
"background_color": "#0175C2",
"theme_color": "#0175C2",
"description": "An example of the url_launcher on the web.",
"orientation": "portrait-primary",
"prefer_related_applications": false,
"icons": [
{
"src": "icons/Icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/Icon-512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
flutter/ephemeral/
# Visual Studio user-specific files.
*.suo
*.user
*.userosscache
*.sln.docstates
# Visual Studio build-related files.
x64/
x86/
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
cmake_minimum_required(VERSION 3.15)
project(example LANGUAGES CXX)
set(BINARY_NAME "example")
cmake_policy(SET CMP0063 NEW)
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
# Configure build options.
get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(IS_MULTICONFIG)
set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
CACHE STRING "" FORCE)
else()
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "Debug" CACHE
STRING "Flutter build mode" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Profile" "Release")
endif()
endif()
set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}")
set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
# Use Unicode for all projects.
add_definitions(-DUNICODE -D_UNICODE)
# Compilation settings that should be applied to most targets.
function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_features(${TARGET} PUBLIC cxx_std_17)
target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100")
target_compile_options(${TARGET} PRIVATE /EHsc)
target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0")
target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>")
endfunction()
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
# Flutter library and tool build rules.
add_subdirectory(${FLUTTER_MANAGED_DIR})
# Application build
add_subdirectory("runner")
# Generated plugin build rules, which manage building the plugins and adding
# them to the application.
include(flutter/generated_plugins.cmake)
# === Installation ===
# Support files are copied into place next to the executable, so that it can
# run in place. This is done instead of making a separate bundle (as on Linux)
# so that building and running from within Visual Studio will work.
set(BUILD_BUNDLE_DIR "$<TARGET_FILE_DIR:${BINARY_NAME}>")
# Make the "install" step default, as it's required to run.
set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
endif()
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
COMPONENT Runtime)
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
COMPONENT Runtime)
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
if(PLUGIN_BUNDLED_LIBRARIES)
install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
endif()
# Fully re-copy the assets directory on each build to avoid having stale files
# from a previous install.
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
install(CODE "
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
" COMPONENT Runtime)
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
# Install the AOT library on non-Debug builds only.
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
CONFIGURATIONS Profile;Release
COMPONENT Runtime)
cmake_minimum_required(VERSION 3.15)
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
# Configuration provided via flutter tool.
include(${EPHEMERAL_DIR}/generated_config.cmake)
# TODO: Move the rest of this into files in ephemeral. See
# https://github.com/flutter/flutter/issues/57146.
set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
# === Flutter Library ===
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")
# Published to parent scope for install step.
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE)
list(APPEND FLUTTER_LIBRARY_HEADERS
"flutter_export.h"
"flutter_windows.h"
"flutter_messenger.h"
"flutter_plugin_registrar.h"
)
list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/")
add_library(flutter INTERFACE)
target_include_directories(flutter INTERFACE
"${EPHEMERAL_DIR}"
)
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib")
add_dependencies(flutter flutter_assemble)
# === Wrapper ===
list(APPEND CPP_WRAPPER_SOURCES_CORE
"core_implementations.cc"
"standard_codec.cc"
)
list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/")
list(APPEND CPP_WRAPPER_SOURCES_PLUGIN
"plugin_registrar.cc"
)
list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/")
list(APPEND CPP_WRAPPER_SOURCES_APP
"flutter_engine.cc"
"flutter_view_controller.cc"
)
list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/")
# Wrapper sources needed for a plugin.
add_library(flutter_wrapper_plugin STATIC
${CPP_WRAPPER_SOURCES_CORE}
${CPP_WRAPPER_SOURCES_PLUGIN}
)
apply_standard_settings(flutter_wrapper_plugin)
set_target_properties(flutter_wrapper_plugin PROPERTIES
POSITION_INDEPENDENT_CODE ON)
set_target_properties(flutter_wrapper_plugin PROPERTIES
CXX_VISIBILITY_PRESET hidden)
target_link_libraries(flutter_wrapper_plugin PUBLIC flutter)
target_include_directories(flutter_wrapper_plugin PUBLIC
"${WRAPPER_ROOT}/include"
)
add_dependencies(flutter_wrapper_plugin flutter_assemble)
# Wrapper sources needed for the runner.
add_library(flutter_wrapper_app STATIC
${CPP_WRAPPER_SOURCES_CORE}
${CPP_WRAPPER_SOURCES_APP}
)
apply_standard_settings(flutter_wrapper_app)
target_link_libraries(flutter_wrapper_app PUBLIC flutter)
target_include_directories(flutter_wrapper_app PUBLIC
"${WRAPPER_ROOT}/include"
)
add_dependencies(flutter_wrapper_app flutter_assemble)
# === Flutter tool backend ===
# _phony_ is a non-existent file to force this command to run every time,
# since currently there's no way to get a full input/output list from the
# flutter tool.
set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_")
set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE)
add_custom_command(
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN}
${CPP_WRAPPER_SOURCES_APP}
${PHONY_OUTPUT}
COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
windows-x64 $<CONFIG>
)
add_custom_target(flutter_assemble DEPENDS
"${FLUTTER_LIBRARY}"
${FLUTTER_LIBRARY_HEADERS}
${CPP_WRAPPER_SOURCES_CORE}
${CPP_WRAPPER_SOURCES_PLUGIN}
${CPP_WRAPPER_SOURCES_APP}
)
//
// Generated file. Do not edit.
//
#include "generated_plugin_registrant.h"
#include <url_launcher_windows/url_launcher_plugin.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
UrlLauncherPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherPlugin"));
}
//
// Generated file. Do not edit.
//
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
#include <flutter/plugin_registry.h>
// Registers Flutter plugins.
void RegisterPlugins(flutter::PluginRegistry* registry);
#endif // GENERATED_PLUGIN_REGISTRANT_
#
# Generated file, do not edit.
#
list(APPEND FLUTTER_PLUGIN_LIST
url_launcher_windows
)
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin})
target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)
cmake_minimum_required(VERSION 3.15)
project(runner LANGUAGES CXX)
add_executable(${BINARY_NAME} WIN32
"flutter_window.cpp"
"main.cpp"
"run_loop.cpp"
"utils.cpp"
"win32_window.cpp"
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
"Runner.rc"
"runner.exe.manifest"
)
apply_standard_settings(${BINARY_NAME})
target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
add_dependencies(${BINARY_NAME} flutter_assemble)
// Microsoft Visual C++ generated resource script.
//
#pragma code_page(65001)
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_APP_ICON ICON "resources\\app_icon.ico"
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
#ifdef FLUTTER_BUILD_NUMBER
#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER
#else
#define VERSION_AS_NUMBER 1,0,0
#endif
#ifdef FLUTTER_BUILD_NAME
#define VERSION_AS_STRING #FLUTTER_BUILD_NAME
#else
#define VERSION_AS_STRING "1.0.0"
#endif
VS_VERSION_INFO VERSIONINFO
FILEVERSION VERSION_AS_NUMBER
PRODUCTVERSION VERSION_AS_NUMBER
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS__WINDOWS32
FILETYPE VFT_APP
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904e4"
BEGIN
VALUE "CompanyName", "io.flutter.plugins" "\0"
VALUE "FileDescription", "A new Flutter project." "\0"
VALUE "FileVersion", VERSION_AS_STRING "\0"
VALUE "InternalName", "example" "\0"
VALUE "LegalCopyright", "Copyright (C) 2020 io.flutter.plugins. All rights reserved." "\0"
VALUE "OriginalFilename", "example.exe" "\0"
VALUE "ProductName", "example" "\0"
VALUE "ProductVersion", VERSION_AS_STRING "\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1252
END
END
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
#include "flutter_window.h"
#include <optional>
#include "flutter/generated_plugin_registrant.h"
FlutterWindow::FlutterWindow(RunLoop* run_loop,
const flutter::DartProject& project)
: run_loop_(run_loop), project_(project) {}
FlutterWindow::~FlutterWindow() {}
bool FlutterWindow::OnCreate() {
if (!Win32Window::OnCreate()) {
return false;
}
RECT frame = GetClientArea();
// The size here must match the window dimensions to avoid unnecessary surface
// creation / destruction in the startup path.
flutter_controller_ = std::make_unique<flutter::FlutterViewController>(
frame.right - frame.left, frame.bottom - frame.top, project_);
// Ensure that basic setup of the controller was successful.
if (!flutter_controller_->engine() || !flutter_controller_->view()) {
return false;
}
RegisterPlugins(flutter_controller_->engine());
run_loop_->RegisterFlutterInstance(flutter_controller_->engine());
SetChildContent(flutter_controller_->view()->GetNativeWindow());
return true;
}
void FlutterWindow::OnDestroy() {
if (flutter_controller_) {
run_loop_->UnregisterFlutterInstance(flutter_controller_->engine());
flutter_controller_ = nullptr;
}
Win32Window::OnDestroy();
}
LRESULT
FlutterWindow::MessageHandler(HWND hwnd, UINT const message,
WPARAM const wparam,
LPARAM const lparam) noexcept {
// Give Flutter, including plugins, an opporutunity to handle window messages.
if (flutter_controller_) {
std::optional<LRESULT> result =
flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,
lparam);
if (result) {
return *result;
}
}
switch (message) {
case WM_FONTCHANGE:
flutter_controller_->engine()->ReloadSystemFonts();
break;
}
return Win32Window::MessageHandler(hwnd, message, wparam, lparam);
}
#ifndef RUNNER_FLUTTER_WINDOW_H_
#define RUNNER_FLUTTER_WINDOW_H_
#include <flutter/dart_project.h>
#include <flutter/flutter_view_controller.h>
#include <memory>
#include "run_loop.h"
#include "win32_window.h"
// A window that does nothing but host a Flutter view.
class FlutterWindow : public Win32Window {
public:
// Creates a new FlutterWindow driven by the |run_loop|, hosting a
// Flutter view running |project|.
explicit FlutterWindow(RunLoop* run_loop,
const flutter::DartProject& project);
virtual ~FlutterWindow();
protected:
// Win32Window:
bool OnCreate() override;
void OnDestroy() override;
LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,
LPARAM const lparam) noexcept override;
private:
// The run loop driving events for this window.
RunLoop* run_loop_;
// The project to run.
flutter::DartProject project_;
// The Flutter instance hosted by this window.
std::unique_ptr<flutter::FlutterViewController> flutter_controller_;
};
#endif // RUNNER_FLUTTER_WINDOW_H_
#include <flutter/dart_project.h>
#include <flutter/flutter_view_controller.h>
#include <windows.h>
#include "flutter_window.h"
#include "run_loop.h"
#include "utils.h"
int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
_In_ wchar_t *command_line, _In_ int show_command) {
// Attach to console when present (e.g., 'flutter run') or create a
// new console when running with a debugger.
if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
CreateAndAttachConsole();
}
// Initialize COM, so that it is available for use in the library and/or
// plugins.
::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
RunLoop run_loop;
flutter::DartProject project(L"data");
FlutterWindow window(&run_loop, project);
Win32Window::Point origin(10, 10);
Win32Window::Size size(1280, 720);
if (!window.CreateAndShow(L"example", origin, size)) {
return EXIT_FAILURE;
}
window.SetQuitOnClose(true);
run_loop.Run();
::CoUninitialize();
return EXIT_SUCCESS;
}
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by Runner.rc
//
#define IDI_APP_ICON 101
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
#include "run_loop.h"
#include <windows.h>
#include <algorithm>
RunLoop::RunLoop() {}
RunLoop::~RunLoop() {}
void RunLoop::Run() {
bool keep_running = true;
TimePoint next_flutter_event_time = TimePoint::clock::now();
while (keep_running) {
std::chrono::nanoseconds wait_duration =
std::max(std::chrono::nanoseconds(0),
next_flutter_event_time - TimePoint::clock::now());
::MsgWaitForMultipleObjects(
0, nullptr, FALSE, static_cast<DWORD>(wait_duration.count() / 1000),
QS_ALLINPUT);
bool processed_events = false;
MSG message;
// All pending Windows messages must be processed; MsgWaitForMultipleObjects
// won't return again for items left in the queue after PeekMessage.
while (::PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) {
processed_events = true;
if (message.message == WM_QUIT) {
keep_running = false;
break;
}
::TranslateMessage(&message);
::DispatchMessage(&message);
// Allow Flutter to process messages each time a Windows message is
// processed, to prevent starvation.
next_flutter_event_time =
std::min(next_flutter_event_time, ProcessFlutterMessages());
}
// If the PeekMessage loop didn't run, process Flutter messages.
if (!processed_events) {
next_flutter_event_time =
std::min(next_flutter_event_time, ProcessFlutterMessages());
}
}
}
void RunLoop::RegisterFlutterInstance(
flutter::FlutterEngine* flutter_instance) {
flutter_instances_.insert(flutter_instance);
}
void RunLoop::UnregisterFlutterInstance(
flutter::FlutterEngine* flutter_instance) {
flutter_instances_.erase(flutter_instance);
}
RunLoop::TimePoint RunLoop::ProcessFlutterMessages() {
TimePoint next_event_time = TimePoint::max();
for (auto instance : flutter_instances_) {
std::chrono::nanoseconds wait_duration = instance->ProcessMessages();
if (wait_duration != std::chrono::nanoseconds::max()) {
next_event_time =
std::min(next_event_time, TimePoint::clock::now() + wait_duration);
}
}
return next_event_time;
}
#ifndef RUNNER_RUN_LOOP_H_
#define RUNNER_RUN_LOOP_H_
#include <flutter/flutter_engine.h>
#include <chrono>
#include <set>
// A runloop that will service events for Flutter instances as well
// as native messages.
class RunLoop {
public:
RunLoop();
~RunLoop();
// Prevent copying
RunLoop(RunLoop const&) = delete;
RunLoop& operator=(RunLoop const&) = delete;
// Runs the run loop until the application quits.
void Run();
// Registers the given Flutter instance for event servicing.
void RegisterFlutterInstance(flutter::FlutterEngine* flutter_instance);
// Unregisters the given Flutter instance from event servicing.
void UnregisterFlutterInstance(flutter::FlutterEngine* flutter_instance);
private:
using TimePoint = std::chrono::steady_clock::time_point;
// Processes all currently pending messages for registered Flutter instances.
TimePoint ProcessFlutterMessages();
std::set<flutter::FlutterEngine*> flutter_instances_;
};
#endif // RUNNER_RUN_LOOP_H_
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</windowsSettings>
</application>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
</application>
</compatibility>
</assembly>
#include "utils.h"
#include <flutter_windows.h>
#include <io.h>
#include <stdio.h>
#include <windows.h>
#include <iostream>
void CreateAndAttachConsole() {
if (::AllocConsole()) {
FILE *unused;
if (freopen_s(&unused, "CONOUT$", "w", stdout)) {
_dup2(_fileno(stdout), 1);
}
if (freopen_s(&unused, "CONOUT$", "w", stderr)) {
_dup2(_fileno(stdout), 2);
}
std::ios::sync_with_stdio();
FlutterDesktopResyncOutputStreams();
}
}
#ifndef RUNNER_UTILS_H_
#define RUNNER_UTILS_H_
// Creates a console for the process, and redirects stdout and stderr to
// it for both the runner and the Flutter library.
void CreateAndAttachConsole();
#endif // RUNNER_UTILS_H_
#include "win32_window.h"
#include <flutter_windows.h>
#include "resource.h"
namespace {
constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW";
// The number of Win32Window objects that currently exist.
static int g_active_window_count = 0;
using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd);
// Scale helper to convert logical scaler values to physical using passed in
// scale factor
int Scale(int source, double scale_factor) {
return static_cast<int>(source * scale_factor);
}
// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module.
// This API is only needed for PerMonitor V1 awareness mode.
void EnableFullDpiSupportIfAvailable(HWND hwnd) {
HMODULE user32_module = LoadLibraryA("User32.dll");
if (!user32_module) {
return;
}
auto enable_non_client_dpi_scaling =
reinterpret_cast<EnableNonClientDpiScaling*>(
GetProcAddress(user32_module, "EnableNonClientDpiScaling"));
if (enable_non_client_dpi_scaling != nullptr) {
enable_non_client_dpi_scaling(hwnd);
FreeLibrary(user32_module);
}
}
} // namespace
// Manages the Win32Window's window class registration.
class WindowClassRegistrar {
public:
~WindowClassRegistrar() = default;
// Returns the singleton registar instance.
static WindowClassRegistrar* GetInstance() {
if (!instance_) {
instance_ = new WindowClassRegistrar();
}
return instance_;
}
// Returns the name of the window class, registering the class if it hasn't
// previously been registered.
const wchar_t* GetWindowClass();
// Unregisters the window class. Should only be called if there are no
// instances of the window.
void UnregisterWindowClass();
private:
WindowClassRegistrar() = default;
static WindowClassRegistrar* instance_;
bool class_registered_ = false;
};
WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr;
const wchar_t* WindowClassRegistrar::GetWindowClass() {
if (!class_registered_) {
WNDCLASS window_class{};
window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
window_class.lpszClassName = kWindowClassName;
window_class.style = CS_HREDRAW | CS_VREDRAW;
window_class.cbClsExtra = 0;
window_class.cbWndExtra = 0;
window_class.hInstance = GetModuleHandle(nullptr);
window_class.hIcon =
LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON));
window_class.hbrBackground = 0;
window_class.lpszMenuName = nullptr;
window_class.lpfnWndProc = Win32Window::WndProc;
RegisterClass(&window_class);
class_registered_ = true;
}
return kWindowClassName;
}
void WindowClassRegistrar::UnregisterWindowClass() {
UnregisterClass(kWindowClassName, nullptr);
class_registered_ = false;
}
Win32Window::Win32Window() { ++g_active_window_count; }
Win32Window::~Win32Window() {
--g_active_window_count;
Destroy();
}
bool Win32Window::CreateAndShow(const std::wstring& title, const Point& origin,
const Size& size) {
Destroy();
const wchar_t* window_class =
WindowClassRegistrar::GetInstance()->GetWindowClass();
const POINT target_point = {static_cast<LONG>(origin.x),
static_cast<LONG>(origin.y)};
HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST);
UINT dpi = FlutterDesktopGetDpiForMonitor(monitor);
double scale_factor = dpi / 96.0;
HWND window = CreateWindow(
window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE,
Scale(origin.x, scale_factor), Scale(origin.y, scale_factor),
Scale(size.width, scale_factor), Scale(size.height, scale_factor),
nullptr, nullptr, GetModuleHandle(nullptr), this);
if (!window) {
return false;
}
return OnCreate();
}
// static
LRESULT CALLBACK Win32Window::WndProc(HWND const window, UINT const message,
WPARAM const wparam,
LPARAM const lparam) noexcept {
if (message == WM_NCCREATE) {
auto window_struct = reinterpret_cast<CREATESTRUCT*>(lparam);
SetWindowLongPtr(window, GWLP_USERDATA,
reinterpret_cast<LONG_PTR>(window_struct->lpCreateParams));
auto that = static_cast<Win32Window*>(window_struct->lpCreateParams);
EnableFullDpiSupportIfAvailable(window);
that->window_handle_ = window;
} else if (Win32Window* that = GetThisFromHandle(window)) {
return that->MessageHandler(window, message, wparam, lparam);
}
return DefWindowProc(window, message, wparam, lparam);
}
LRESULT
Win32Window::MessageHandler(HWND hwnd, UINT const message, WPARAM const wparam,
LPARAM const lparam) noexcept {
switch (message) {
case WM_DESTROY:
window_handle_ = nullptr;
Destroy();
if (quit_on_close_) {
PostQuitMessage(0);
}
return 0;
case WM_DPICHANGED: {
auto newRectSize = reinterpret_cast<RECT*>(lparam);
LONG newWidth = newRectSize->right - newRectSize->left;
LONG newHeight = newRectSize->bottom - newRectSize->top;
SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth,
newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
return 0;
}
case WM_SIZE:
RECT rect = GetClientArea();
if (child_content_ != nullptr) {
// Size and position the child window.
MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left,
rect.bottom - rect.top, TRUE);
}
return 0;
case WM_ACTIVATE:
if (child_content_ != nullptr) {
SetFocus(child_content_);
}
return 0;
}
return DefWindowProc(window_handle_, message, wparam, lparam);
}
void Win32Window::Destroy() {
OnDestroy();
if (window_handle_) {
DestroyWindow(window_handle_);
window_handle_ = nullptr;
}
if (g_active_window_count == 0) {
WindowClassRegistrar::GetInstance()->UnregisterWindowClass();
}
}
Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept {
return reinterpret_cast<Win32Window*>(
GetWindowLongPtr(window, GWLP_USERDATA));
}
void Win32Window::SetChildContent(HWND content) {
child_content_ = content;
SetParent(content, window_handle_);
RECT frame = GetClientArea();
MoveWindow(content, frame.left, frame.top, frame.right - frame.left,
frame.bottom - frame.top, true);
SetFocus(child_content_);
}
RECT Win32Window::GetClientArea() {
RECT frame;
GetClientRect(window_handle_, &frame);
return frame;
}
HWND Win32Window::GetHandle() { return window_handle_; }
void Win32Window::SetQuitOnClose(bool quit_on_close) {
quit_on_close_ = quit_on_close;
}
bool Win32Window::OnCreate() {
// No-op; provided for subclasses.
return true;
}
void Win32Window::OnDestroy() {
// No-op; provided for subclasses.
}
#ifndef RUNNER_WIN32_WINDOW_H_
#define RUNNER_WIN32_WINDOW_H_
#include <windows.h>
#include <functional>
#include <memory>
#include <string>
// A class abstraction for a high DPI-aware Win32 Window. Intended to be
// inherited from by classes that wish to specialize with custom
// rendering and input handling
class Win32Window {
public:
struct Point {
unsigned int x;
unsigned int y;
Point(unsigned int x, unsigned int y) : x(x), y(y) {}
};
struct Size {
unsigned int width;
unsigned int height;
Size(unsigned int width, unsigned int height)
: width(width), height(height) {}
};
Win32Window();
virtual ~Win32Window();
// Creates and shows a win32 window with |title| and position and size using
// |origin| and |size|. New windows are created on the default monitor. Window
// sizes are specified to the OS in physical pixels, hence to ensure a
// consistent size to will treat the width height passed in to this function
// as logical pixels and scale to appropriate for the default monitor. Returns
// true if the window was created successfully.
bool CreateAndShow(const std::wstring& title, const Point& origin,
const Size& size);
// Release OS resources associated with window.
void Destroy();
// Inserts |content| into the window tree.
void SetChildContent(HWND content);
// Returns the backing Window handle to enable clients to set icon and other
// window properties. Returns nullptr if the window has been destroyed.
HWND GetHandle();
// If true, closing this window will quit the application.
void SetQuitOnClose(bool quit_on_close);
// Return a RECT representing the bounds of the current client area.
RECT GetClientArea();
protected:
// Processes and route salient window messages for mouse handling,
// size change and DPI. Delegates handling of these to member overloads that
// inheriting classes can handle.
virtual LRESULT MessageHandler(HWND window, UINT const message,
WPARAM const wparam,
LPARAM const lparam) noexcept;
// Called when CreateAndShow is called, allowing subclass window-related
// setup. Subclasses should return false if setup fails.
virtual bool OnCreate();
// Called when Destroy is called.
virtual void OnDestroy();
private:
friend class WindowClassRegistrar;
// OS callback called by message pump. Handles the WM_NCCREATE message which
// is passed when the non-client area is being created and enables automatic
// non-client DPI scaling so that the non-client area automatically
// responsponds to changes in DPI. All other messages are handled by
// MessageHandler.
static LRESULT CALLBACK WndProc(HWND const window, UINT const message,
WPARAM const wparam,
LPARAM const lparam) noexcept;
// Retrieves a class instance pointer for |window|
static Win32Window* GetThisFromHandle(HWND const window) noexcept;
bool quit_on_close_ = false;
// window handle for top level window.
HWND window_handle_ = nullptr;
// window handle for hosted content.
HWND child_content_ = nullptr;
};
#endif // RUNNER_WIN32_WINDOW_H_
// 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
// 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 "FLTURLLauncherPlugin.h"
API_AVAILABLE(ios(9.0))
@interface FLTURLLaunchSession : NSObject <SFSafariViewControllerDelegate>
@property(copy, nonatomic) FlutterResult flutterResult;
@property(strong, nonatomic) NSURL *url;
@property(strong, nonatomic) SFSafariViewController *safari;
@property(nonatomic, copy) void (^didFinish)(void);
@end
@implementation FLTURLLaunchSession
- (instancetype)initWithUrl:url withFlutterResult:result {
self = [super init];
if (self) {
self.url = url;
self.flutterResult = result;
if (@available(iOS 9.0, *)) {
self.safari = [[SFSafariViewController alloc] initWithURL:url];
self.safari.delegate = self;
}
}
return self;
}
- (void)safariViewController:(SFSafariViewController *)controller
didCompleteInitialLoad:(BOOL)didLoadSuccessfully API_AVAILABLE(ios(9.0)) {
if (didLoadSuccessfully) {
self.flutterResult(nil);
} else {
self.flutterResult([FlutterError
errorWithCode:@"Error"
message:[NSString stringWithFormat:@"Error while launching %@", self.url]
details:nil]);
}
}
- (void)safariViewControllerDidFinish:(SFSafariViewController *)controller API_AVAILABLE(ios(9.0)) {
[controller dismissViewControllerAnimated:YES completion:nil];
self.didFinish();
}
- (void)close {
[self safariViewControllerDidFinish:self.safari];
}
@end
API_AVAILABLE(ios(9.0))
@interface FLTURLLauncherPlugin ()
@property(strong, nonatomic) FLTURLLaunchSession *currentSession;
@end
@implementation FLTURLLauncherPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
FlutterMethodChannel *channel =
[FlutterMethodChannel methodChannelWithName:@"plugins.flutter.io/url_launcher"
binaryMessenger:registrar.messenger];
FLTURLLauncherPlugin *plugin = [[FLTURLLauncherPlugin alloc] init];
[registrar addMethodCallDelegate:plugin channel:channel];
}
- (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) {
if (@available(iOS 9.0, *)) {
[self launchURLInVC:url result:result];
} else {
[self launchURL:url call:call result:result];
}
} else {
[self launchURL:url call:call result:result];
}
} else if ([@"closeWebView" isEqualToString:call.method]) {
if (@available(iOS 9.0, *)) {
[self closeWebViewWithResult:result];
} else {
result([FlutterError
errorWithCode:@"API_NOT_AVAILABLE"
message:@"SafariViewController related api is not availabe for version <= IOS9"
details:nil]);
}
} else {
result(FlutterMethodNotImplemented);
}
}
- (BOOL)canLaunchURL:(NSString *)urlString {
NSURL *url = [NSURL URLWithString:urlString];
UIApplication *application = [UIApplication sharedApplication];
return [application canOpenURL:url];
}
- (void)launchURL:(NSString *)urlString
call:(FlutterMethodCall *)call
result:(FlutterResult)result {
NSURL *url = [NSURL URLWithString:urlString];
UIApplication *application = [UIApplication sharedApplication];
if (@available(iOS 10.0, *)) {
NSNumber *universalLinksOnly = call.arguments[@"universalLinksOnly"] ?: @0;
NSDictionary *options = @{UIApplicationOpenURLOptionUniversalLinksOnly : universalLinksOnly};
[application openURL:url
options:options
completionHandler:^(BOOL success) {
result(@(success));
}];
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
BOOL success = [application openURL:url];
#pragma clang diagnostic pop
result(@(success));
}
}
- (void)launchURLInVC:(NSString *)urlString result:(FlutterResult)result API_AVAILABLE(ios(9.0)) {
NSURL *url = [NSURL URLWithString:urlString];
self.currentSession = [[FLTURLLaunchSession alloc] initWithUrl:url withFlutterResult:result];
__weak typeof(self) weakSelf = self;
self.currentSession.didFinish = ^(void) {
weakSelf.currentSession = nil;
};
[self.topViewController presentViewController:self.currentSession.safari
animated:YES
completion:nil];
}
- (void)closeWebViewWithResult:(FlutterResult)result API_AVAILABLE(ios(9.0)) {
if (self.currentSession != nil) {
[self.currentSession close];
}
result(nil);
}
- (UIViewController *)topViewController {
return [self topViewControllerFromViewController:[UIApplication sharedApplication]
.keyWindow.rootViewController];
}
/**
* This method recursively iterate through the view hierarchy
* to return the top most view controller.
*
* It supports the following scenarios:
*
* - The view controller is presenting another view.
* - The view controller is a UINavigationController.
* - The view controller is a UITabBarController.
*
* @return The top most view controller.
*/
- (UIViewController *)topViewControllerFromViewController:(UIViewController *)viewController {
if ([viewController isKindOfClass:[UINavigationController class]]) {
UINavigationController *navigationController = (UINavigationController *)viewController;
return [self
topViewControllerFromViewController:[navigationController.viewControllers lastObject]];
}
if ([viewController isKindOfClass:[UITabBarController class]]) {
UITabBarController *tabController = (UITabBarController *)viewController;
return [self topViewControllerFromViewController:tabController.selectedViewController];
}
if (viewController.presentedViewController) {
return [self topViewControllerFromViewController:viewController.presentedViewController];
}
return viewController;
}
@end
#
# 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 = { :type => 'BSD', :file => '../LICENSE' }
s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
s.source = { :http => 'https://github.com/flutter/plugins/tree/master/packages/url_launcher' }
s.documentation_url = 'https://pub.dev/packages/url_launcher'
s.source_files = 'Classes/**/*'
s.public_header_files = 'Classes/**/*.h'
s.dependency 'Flutter'
s.platform = :ios, '8.0'
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' }
end
// 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.
export 'src/link.dart' show Link;
export 'package:url_launcher_platform_interface/link.dart'
show FollowLink, LinkTarget, LinkWidgetBuilder;
// 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/widgets.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:url_launcher_platform_interface/link.dart';
import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart';
/// A widget that renders a real link on the web, and uses WebViews in native
/// platforms to open links.
///
/// Example link to an external URL:
///
/// ```dart
/// Link(
/// uri: Uri.parse('https://flutter.dev'),
/// builder: (BuildContext context, FollowLink followLink) => RaisedButton(
/// onPressed: followLink,
/// // ... other properties here ...
/// )},
/// );
/// ```
///
/// Example link to a route name within the app:
///
/// ```dart
/// Link(
/// uri: Uri.parse('/home'),
/// builder: (BuildContext context, FollowLink followLink) => RaisedButton(
/// onPressed: followLink,
/// // ... other properties here ...
/// )},
/// );
/// ```
class Link extends StatelessWidget implements LinkInfo {
/// Called at build time to construct the widget tree under the link.
final LinkWidgetBuilder builder;
/// The destination that this link leads to.
final Uri uri;
/// The target indicating where to open the link.
final LinkTarget target;
/// Whether the link is disabled or not.
bool get isDisabled => uri == null;
/// Creates a widget that renders a real link on the web, and uses WebViews in
/// native platforms to open links.
Link({
Key key,
@required this.uri,
LinkTarget target,
@required this.builder,
}) : target = target ?? LinkTarget.defaultTarget,
super(key: key);
LinkDelegate get _effectiveDelegate {
return UrlLauncherPlatform.instance.linkDelegate ??
DefaultLinkDelegate.create;
}
@override
Widget build(BuildContext context) {
return _effectiveDelegate(this);
}
}
/// The default delegate used on non-web platforms.
///
/// For external URIs, it uses url_launche APIs. For app route names, it uses
/// event channel messages to instruct the framework to push the route name.
class DefaultLinkDelegate extends StatelessWidget {
/// Creates a delegate for the given [link].
const DefaultLinkDelegate(this.link);
/// Given a [link], creates an instance of [DefaultLinkDelegate].
///
/// This is a static method so it can be used as a tear-off.
static DefaultLinkDelegate create(LinkInfo link) {
return DefaultLinkDelegate(link);
}
/// Information about the link built by the app.
final LinkInfo link;
bool get _useWebView {
if (link.target == LinkTarget.self) return true;
if (link.target == LinkTarget.blank) return false;
return null;
}
Future<void> _followLink(BuildContext context) async {
if (!link.uri.hasScheme) {
// A uri that doesn't have a scheme is an internal route name. In this
// case, we push it via Flutter's navigation system instead of letting the
// browser handle it.
final String routeName = link.uri.toString();
return pushRouteNameToFramework(context, routeName);
}
// At this point, we know that the link is external. So we use the `launch`
// API to open the link.
final String urlString = link.uri.toString();
if (await canLaunch(urlString)) {
await launch(
urlString,
forceSafariVC: _useWebView,
forceWebView: _useWebView,
);
} else {
FlutterError.reportError(FlutterErrorDetails(
exception: 'Could not launch link $urlString',
stack: StackTrace.current,
library: 'url_launcher',
context: ErrorDescription('during launching a link'),
));
}
return Future<void>.value(null);
}
@override
Widget build(BuildContext context) {
return link.builder(
context,
link.isDisabled ? null : () => _followLink(context),
);
}
}
// 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';
import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart';
/// 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 with iOS version >= 9.0. By default (when unset), the launcher
/// opens web URLs in the Safari View Controller, 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. Note that to work with universal links on iOS,
/// this must be set to false to let the platform's system handle the URL.
/// Set this to false if you want to use the cookies/context of the main browser
/// of the app (such as SSO flows). This setting will nullify [universalLinksOnly]
/// and will always launch a web content in the built-in Safari View Controller regardless
/// if the url is a universal link or not.
///
/// [universalLinksOnly] is only used in iOS with iOS version >= 10.0. This setting is only validated
/// when [forceSafariVC] is set to false. The default value of this setting is false.
/// By default (when unset), the launcher will either launch the url in a browser (when the
/// url is not a universal link), or launch the respective native app content (when
/// the url is a universal link). When set to true, the launcher will only launch
/// the content if the url is a universal link and the respective app for the universal
/// link is installed on the user's device; otherwise throw a [PlatformException].
///
/// [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.
/// [enableDomStorage] is an Android only setting. If true, WebView enable
/// DOM storage.
/// [headers] is an Android only setting that adds headers to the WebView.
/// When not using a WebView, the header information is passed to the browser,
/// some Android browsers do not support the [Browser.EXTRA_HEADERS](https://developer.android.com/reference/android/provider/Browser#EXTRA_HEADERS)
/// intent extra and the header information will be lost.
/// [webOnlyWindowName] is an Web only setting . _blank opens the new url in new tab ,
/// _self opens the new url in current tab.
/// Default behaviour is to open the url in new tab.
///
/// 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 resetting the previous status bar style.
///
/// Returns true if launch url is successful; false is only returned when [universalLinksOnly]
/// is set to true and the universal link failed to launch.
Future<bool> launch(
String urlString, {
bool forceSafariVC,
bool forceWebView,
bool enableJavaScript,
bool enableDomStorage,
bool universalLinksOnly,
Map<String, String> headers,
Brightness statusBarBrightness,
String webOnlyWindowName,
}) async {
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.');
}
/// [true] so that ui is automatically computed if [statusBarBrightness] is set.
bool previousAutomaticSystemUiAdjustment = true;
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);
}
final bool result = await UrlLauncherPlatform.instance.launch(
urlString,
useSafariVC: forceSafariVC ?? isWebURL,
useWebView: forceWebView ?? false,
enableJavaScript: enableJavaScript ?? false,
enableDomStorage: enableDomStorage ?? false,
universalLinksOnly: universalLinksOnly ?? false,
headers: headers ?? <String, String>{},
webOnlyWindowName: webOnlyWindowName,
);
assert(previousAutomaticSystemUiAdjustment != null);
if (statusBarBrightness != null) {
WidgetsBinding.instance.renderView.automaticSystemUiAdjustment =
previousAutomaticSystemUiAdjustment;
}
return result;
}
/// Checks whether the specified URL can be handled by some app installed on the
/// device.
///
/// On Android (from API 30), [canLaunch] will return `false` when the required
/// visibility configuration is not provided in the AndroidManifest.xml file.
/// For more information see the [Managing package visibility](https://developer.android.com/training/basics/intents/package-visibility)
/// article in the Android docs.
Future<bool> canLaunch(String urlString) async {
if (urlString == null) {
return false;
}
return await UrlLauncherPlatform.instance.canLaunch(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`
/// Or on IOS systems, if [launch] was called without `forceSafariVC` being set to `true`,
/// this call will not do anything either, simply because there is no
/// WebView/SafariViewController available to be closed.
///
/// SafariViewController is only available on IOS version >= 9.0, this method does not do anything
/// on IOS version below 9.0
Future<void> closeWebView() async {
return await UrlLauncherPlatform.instance.closeWebView();
}
#
# 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 = 'No-op implementation of the macos url_launcher to avoid build issues on macos'
s.description = <<-DESC
No-op implementation of the url_launcher plugin to avoid build issues on macos.
https://github.com/flutter/flutter/issues/46618
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.platform = :osx
s.osx.deployment_target = '10.11'
end
name: url_launcher
description: Flutter plugin for launching a URL on Android and iOS. Supports
web, phone, SMS, and email schemes.
homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher
version: 5.7.10
flutter:
plugin:
platforms:
android:
package: io.flutter.plugins.urllauncher
pluginClass: UrlLauncherPlugin
ios:
pluginClass: FLTURLLauncherPlugin
web:
default_package: url_launcher_web
linux:
default_package: url_laucher_linux
macos:
default_package: url_laucher_macos
windows:
default_package: url_laucher_windows
dependencies:
flutter:
sdk: flutter
url_launcher_platform_interface: ^1.0.9
# The design on https://flutter.dev/go/federated-plugins was to leave
# this constraint as "any". We cannot do it right now as it fails pub publish
# validation, so we set a ^ constraint.
# TODO(amirh): Revisit this (either update this part in the design or the pub tool).
# https://github.com/flutter/flutter/issues/46264
url_launcher_web: ^0.1.5
url_launcher_linux: ^0.0.1
url_launcher_macos: ^0.0.1
url_launcher_windows: ^0.0.1
dev_dependencies:
flutter_test:
sdk: flutter
test: ^1.3.0
mockito: ^4.1.1
plugin_platform_interface: ^1.0.0
pedantic: ^1.8.0
environment:
sdk: ">=2.1.0 <3.0.0"
flutter: ">=1.12.13+hotfix.5 <2.0.0"
// 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.
// @dart = 2.8
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:flutter/services.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'package:url_launcher/link.dart';
import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart';
final MethodCodec _codec = const JSONMethodCodec();
void main() {
final MockUrlLauncher mock = MockUrlLauncher();
UrlLauncherPlatform.instance = mock;
PlatformMessageCallback realOnPlatformMessage;
setUp(() {
realOnPlatformMessage = window.onPlatformMessage;
});
tearDown(() {
window.onPlatformMessage = realOnPlatformMessage;
});
group('$Link', () {
testWidgets('handles null uri correctly', (WidgetTester tester) async {
bool isBuilt = false;
FollowLink followLink;
final Link link = Link(
uri: null,
builder: (BuildContext context, FollowLink followLink2) {
isBuilt = true;
followLink = followLink2;
return Container();
},
);
await tester.pumpWidget(link);
expect(link.isDisabled, isTrue);
expect(isBuilt, isTrue);
expect(followLink, isNull);
});
testWidgets('calls url_launcher for external URLs with blank target',
(WidgetTester tester) async {
FollowLink followLink;
await tester.pumpWidget(Link(
uri: Uri.parse('http://example.com/foobar'),
target: LinkTarget.blank,
builder: (BuildContext context, FollowLink followLink2) {
followLink = followLink2;
return Container();
},
));
when(mock.canLaunch('http://example.com/foobar'))
.thenAnswer((realInvocation) => Future<bool>.value(true));
clearInteractions(mock);
await followLink();
verifyInOrder([
mock.canLaunch('http://example.com/foobar'),
mock.launch(
'http://example.com/foobar',
useSafariVC: false,
useWebView: false,
universalLinksOnly: false,
enableJavaScript: false,
enableDomStorage: false,
headers: <String, String>{},
)
]);
});
testWidgets('calls url_launcher for external URLs with self target',
(WidgetTester tester) async {
FollowLink followLink;
await tester.pumpWidget(Link(
uri: Uri.parse('http://example.com/foobar'),
target: LinkTarget.self,
builder: (BuildContext context, FollowLink followLink2) {
followLink = followLink2;
return Container();
},
));
when(mock.canLaunch('http://example.com/foobar'))
.thenAnswer((realInvocation) => Future<bool>.value(true));
clearInteractions(mock);
await followLink();
verifyInOrder([
mock.canLaunch('http://example.com/foobar'),
mock.launch(
'http://example.com/foobar',
useSafariVC: true,
useWebView: true,
universalLinksOnly: false,
enableJavaScript: false,
enableDomStorage: false,
headers: <String, String>{},
)
]);
});
testWidgets('sends navigation platform messages for internal route names',
(WidgetTester tester) async {
// Intercept messages sent to the engine.
final List<MethodCall> engineCalls = <MethodCall>[];
SystemChannels.navigation.setMockMethodCallHandler((MethodCall call) {
engineCalls.add(call);
return Future<void>.value();
});
// Intercept messages sent to the framework.
final List<MethodCall> frameworkCalls = <MethodCall>[];
window.onPlatformMessage = (
String name,
ByteData data,
PlatformMessageResponseCallback callback,
) {
frameworkCalls.add(_codec.decodeMethodCall(data));
realOnPlatformMessage(name, data, callback);
};
final Uri uri = Uri.parse('/foo/bar');
FollowLink followLink;
await tester.pumpWidget(MaterialApp(
routes: <String, WidgetBuilder>{
'/': (BuildContext context) => Link(
uri: uri,
builder: (BuildContext context, FollowLink followLink2) {
followLink = followLink2;
return Container();
},
),
'/foo/bar': (BuildContext context) => Container(),
},
));
engineCalls.clear();
frameworkCalls.clear();
clearInteractions(mock);
await followLink();
// Shouldn't use url_launcher when uri is an internal route name.
verifyZeroInteractions(mock);
// A message should've been sent to the engine (by the Navigator, not by
// the Link widget).
//
// Even though this message isn't being sent by Link, we still want to
// have a test for it because we rely on it for Link to work correctly.
expect(engineCalls, hasLength(1));
expect(
engineCalls.single,
isMethodCall('routeUpdated', arguments: <dynamic, dynamic>{
'previousRouteName': '/',
'routeName': '/foo/bar',
}),
);
// Pushes route to the framework.
expect(frameworkCalls, hasLength(1));
expect(
frameworkCalls.single,
isMethodCall('pushRoute', arguments: '/foo/bar'),
);
});
testWidgets('sends router platform messages for internal route names',
(WidgetTester tester) async {
// Intercept messages sent to the engine.
final List<MethodCall> engineCalls = <MethodCall>[];
SystemChannels.navigation.setMockMethodCallHandler((MethodCall call) {
engineCalls.add(call);
return Future<void>.value();
});
// Intercept messages sent to the framework.
final List<MethodCall> frameworkCalls = <MethodCall>[];
window.onPlatformMessage = (
String name,
ByteData data,
PlatformMessageResponseCallback callback,
) {
frameworkCalls.add(_codec.decodeMethodCall(data));
realOnPlatformMessage(name, data, callback);
};
final Uri uri = Uri.parse('/foo/bar');
FollowLink followLink;
final Link link = Link(
uri: uri,
builder: (BuildContext context, FollowLink followLink2) {
followLink = followLink2;
return Container();
},
);
await tester.pumpWidget(MaterialApp.router(
routeInformationParser: MockRouteInformationParser(),
routerDelegate: MockRouterDelegate(
builder: (BuildContext context) => link,
),
));
engineCalls.clear();
frameworkCalls.clear();
clearInteractions(mock);
await followLink();
// Shouldn't use url_launcher when uri is an internal route name.
verifyZeroInteractions(mock);
// Sends route information update to the engine.
expect(engineCalls, hasLength(1));
expect(
engineCalls.single,
isMethodCall('routeInformationUpdated', arguments: <dynamic, dynamic>{
'location': '/foo/bar',
'state': null
}),
);
// Also pushes route information update to the Router.
expect(frameworkCalls, hasLength(1));
expect(
frameworkCalls.single,
isMethodCall(
'pushRouteInformation',
arguments: <dynamic, dynamic>{
'location': '/foo/bar',
'state': null,
},
),
);
});
});
}
class MockUrlLauncher extends Mock
with MockPlatformInterfaceMixin
implements UrlLauncherPlatform {}
class MockRouteInformationParser extends Mock
implements RouteInformationParser<bool> {
@override
Future<bool> parseRouteInformation(RouteInformation routeInformation) {
return Future<bool>.value(true);
}
}
class MockRouterDelegate extends Mock implements RouterDelegate {
MockRouterDelegate({@required this.builder});
final WidgetBuilder builder;
@override
Widget build(BuildContext context) {
return builder(context);
}
}
// 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.
// @dart = 2.8
import 'dart:async';
import 'dart:ui';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:flutter/foundation.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart';
import 'package:flutter/services.dart' show PlatformException;
void main() {
final MockUrlLauncher mock = MockUrlLauncher();
UrlLauncherPlatform.instance = mock;
test('closeWebView default behavior', () async {
await closeWebView();
verify(mock.closeWebView());
});
group('canLaunch', () {
test('returns true', () async {
when(mock.canLaunch('foo')).thenAnswer((_) => Future<bool>.value(true));
final bool result = await canLaunch('foo');
expect(result, isTrue);
});
test('returns false', () async {
when(mock.canLaunch('foo')).thenAnswer((_) => Future<bool>.value(false));
final bool result = await canLaunch('foo');
expect(result, isFalse);
});
});
group('launch', () {
test('requires a non-null urlString', () {
expect(() => launch(null), throwsAssertionError);
});
test('default behavior', () async {
await launch('http://flutter.dev/');
expect(
verify(mock.launch(
captureAny,
useSafariVC: captureAnyNamed('useSafariVC'),
useWebView: captureAnyNamed('useWebView'),
enableJavaScript: captureAnyNamed('enableJavaScript'),
enableDomStorage: captureAnyNamed('enableDomStorage'),
universalLinksOnly: captureAnyNamed('universalLinksOnly'),
headers: captureAnyNamed('headers'),
)).captured,
<dynamic>[
'http://flutter.dev/',
true,
false,
false,
false,
false,
<String, String>{},
],
);
});
test('with headers', () async {
await launch(
'http://flutter.dev/',
headers: <String, String>{'key': 'value'},
);
expect(
verify(mock.launch(
any,
useSafariVC: anyNamed('useSafariVC'),
useWebView: anyNamed('useWebView'),
enableJavaScript: anyNamed('enableJavaScript'),
enableDomStorage: anyNamed('enableDomStorage'),
universalLinksOnly: anyNamed('universalLinksOnly'),
headers: captureAnyNamed('headers'),
)).captured.single,
<String, String>{'key': 'value'},
);
});
test('force SafariVC', () async {
await launch('http://flutter.dev/', forceSafariVC: true);
expect(
verify(mock.launch(
any,
useSafariVC: captureAnyNamed('useSafariVC'),
useWebView: anyNamed('useWebView'),
enableJavaScript: anyNamed('enableJavaScript'),
enableDomStorage: anyNamed('enableDomStorage'),
universalLinksOnly: anyNamed('universalLinksOnly'),
headers: anyNamed('headers'),
)).captured.single,
true,
);
});
test('universal links only', () async {
await launch('http://flutter.dev/',
forceSafariVC: false, universalLinksOnly: true);
expect(
verify(mock.launch(
any,
useSafariVC: captureAnyNamed('useSafariVC'),
useWebView: anyNamed('useWebView'),
enableJavaScript: anyNamed('enableJavaScript'),
enableDomStorage: anyNamed('enableDomStorage'),
universalLinksOnly: captureAnyNamed('universalLinksOnly'),
headers: anyNamed('headers'),
)).captured,
<bool>[false, true],
);
});
test('force WebView', () async {
await launch('http://flutter.dev/', forceWebView: true);
expect(
verify(mock.launch(
any,
useSafariVC: anyNamed('useSafariVC'),
useWebView: captureAnyNamed('useWebView'),
enableJavaScript: anyNamed('enableJavaScript'),
enableDomStorage: anyNamed('enableDomStorage'),
universalLinksOnly: anyNamed('universalLinksOnly'),
headers: anyNamed('headers'),
)).captured.single,
true,
);
});
test('force WebView enable javascript', () async {
await launch('http://flutter.dev/',
forceWebView: true, enableJavaScript: true);
expect(
verify(mock.launch(
any,
useSafariVC: anyNamed('useSafariVC'),
useWebView: captureAnyNamed('useWebView'),
enableJavaScript: captureAnyNamed('enableJavaScript'),
enableDomStorage: anyNamed('enableDomStorage'),
universalLinksOnly: anyNamed('universalLinksOnly'),
headers: anyNamed('headers'),
)).captured,
<bool>[true, true],
);
});
test('force WebView enable DOM storage', () async {
await launch('http://flutter.dev/',
forceWebView: true, enableDomStorage: true);
expect(
verify(mock.launch(
any,
useSafariVC: anyNamed('useSafariVC'),
useWebView: captureAnyNamed('useWebView'),
enableJavaScript: anyNamed('enableJavaScript'),
enableDomStorage: captureAnyNamed('enableDomStorage'),
universalLinksOnly: anyNamed('universalLinksOnly'),
headers: anyNamed('headers'),
)).captured,
<bool>[true, true],
);
});
test('force SafariVC to false', () async {
await launch('http://flutter.dev/', forceSafariVC: false);
expect(
// ignore: missing_required_param
verify(mock.launch(
any,
useSafariVC: captureAnyNamed('useSafariVC'),
useWebView: anyNamed('useWebView'),
enableJavaScript: anyNamed('enableJavaScript'),
enableDomStorage: anyNamed('enableDomStorage'),
universalLinksOnly: anyNamed('universalLinksOnly'),
headers: anyNamed('headers'),
)).captured.single,
false,
);
});
test('cannot launch a non-web in webview', () async {
expect(() async => await launch('tel:555-555-5555', forceWebView: true),
throwsA(isA<PlatformException>()));
});
test('controls system UI when changing statusBarBrightness', () async {
final TestWidgetsFlutterBinding binding =
TestWidgetsFlutterBinding.ensureInitialized();
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
binding.renderView.automaticSystemUiAdjustment = true;
final Future<bool> launchResult =
launch('http://flutter.dev/', statusBarBrightness: Brightness.dark);
// Should take over control of the automaticSystemUiAdjustment while it's
// pending, then restore it back to normal after the launch finishes.
expect(binding.renderView.automaticSystemUiAdjustment, isFalse);
await launchResult;
expect(binding.renderView.automaticSystemUiAdjustment, isTrue);
});
test('sets automaticSystemUiAdjustment to not be null', () async {
final TestWidgetsFlutterBinding binding =
TestWidgetsFlutterBinding.ensureInitialized();
debugDefaultTargetPlatformOverride = TargetPlatform.android;
expect(binding.renderView.automaticSystemUiAdjustment, true);
final Future<bool> launchResult =
launch('http://flutter.dev/', statusBarBrightness: Brightness.dark);
// The automaticSystemUiAdjustment should be set before the launch
// and equal to true after the launch result is complete.
expect(binding.renderView.automaticSystemUiAdjustment, true);
await launchResult;
expect(binding.renderView.automaticSystemUiAdjustment, true);
});
});
}
class MockUrlLauncher extends Mock
with MockPlatformInterfaceMixin
implements UrlLauncherPlatform {}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment