| @@ -0,0 +1,66 @@ | |||||
| # Below is a list of people and organizations that have contributed | |||||
| # to the Flutter project. Names should be added to the list like so: | |||||
| # | |||||
| # Name/Organization <email address> | |||||
| Google Inc. | |||||
| The Chromium Authors | |||||
| German Saprykin <saprykin.h@gmail.com> | |||||
| Benjamin Sauer <sauer.benjamin@gmail.com> | |||||
| larsenthomasj@gmail.com | |||||
| Ali Bitek <alibitek@protonmail.ch> | |||||
| Pol Batlló <pol.batllo@gmail.com> | |||||
| Anatoly Pulyaevskiy | |||||
| Hayden Flinner <haydenflinner@gmail.com> | |||||
| Stefano Rodriguez <hlsroddy@gmail.com> | |||||
| Salvatore Giordano <salvatoregiordanoo@gmail.com> | |||||
| Brian Armstrong <brian@flutter.institute> | |||||
| Paul DeMarco <paulmdemarco@gmail.com> | |||||
| Fabricio Nogueira <feufeu@gmail.com> | |||||
| Simon Lightfoot <simon@devangels.london> | |||||
| Ashton Thomas <ashton@acrinta.com> | |||||
| Thomas Danner <thmsdnnr@gmail.com> | |||||
| Diego Velásquez <diego.velasquez.lopez@gmail.com> | |||||
| Hajime Nakamura <nkmrhj@gmail.com> | |||||
| Tuyển Vũ Xuân <netsoft1985@gmail.com> | |||||
| Miguel Ruivo <miguel@miguelruivo.com> | |||||
| Sarthak Verma <sarthak@artiosys.com> | |||||
| Mike Diarmid <mike@invertase.io> | |||||
| Invertase <oss@invertase.io> | |||||
| Elliot Hesp <elliot@invertase.io> | |||||
| Vince Varga <vince.varga@smaho.com> | |||||
| Aawaz Gyawali <awazgyawali@gmail.com> | |||||
| EUI Limited <ian.evans3@admiralgroup.co.uk> | |||||
| Katarina Sheremet <katarina@sheremet.ch> | |||||
| Thomas Stockx <thomas@stockxit.com> | |||||
| Sarbagya Dhaubanjar <sarbagyastha@gmail.com> | |||||
| Ozkan Eksi <ozeksi@gmail.com> | |||||
| Rishab Nayak <rishab@bu.edu> | |||||
| ko2ic <ko2ic.dev@gmail.com> | |||||
| Jonathan Younger <jonathan@daikini.com> | |||||
| Jose Sanchez <josesm82@gmail.com> | |||||
| Debkanchan Samadder <debu.samadder@gmail.com> | |||||
| Audrius Karosevicius <audrius.karosevicius@gmail.com> | |||||
| Lukasz Piliszczuk <lukasz@intheloup.io> | |||||
| SoundReply Solutions GmbH <ch@soundreply.com> | |||||
| Rafal Wachol <rwachol@gmail.com> | |||||
| Pau Picas <pau.picas@gmail.com> | |||||
| Christian Weder <chrstian.weder@yapeal.ch> | |||||
| Alexandru Tuca <salexandru.tuca@outlook.com> | |||||
| Christian Weder <chrstian.weder@yapeal.ch> | |||||
| Rhodes Davis Jr. <rody.davis.jr@gmail.com> | |||||
| Luigi Agosti <luigi@tengio.com> | |||||
| Quentin Le Guennec <quentin@tengio.com> | |||||
| Koushik Ravikumar <koushik@tengio.com> | |||||
| Nissim Dsilva <nissim@tengio.com> | |||||
| Giancarlo Rocha <giancarloiff@gmail.com> | |||||
| Ryo Miyake <ryo@miyake.id> | |||||
| Théo Champion <contact.theochampion@gmail.com> | |||||
| Kazuki Yamaguchi <y.kazuki0614n@gmail.com> | |||||
| Eitan Schwartz <eshvartz@gmail.com> | |||||
| Chris Rutkowski <chrisrutkowski89@gmail.com> | |||||
| Juan Alvarez <juan.alvarez@resideo.com> | |||||
| Aleksandr Yurkovskiy <sanekyy@gmail.com> | |||||
| Anton Borries <mail@antonborri.es> | |||||
| Alex Li <google@alexv525.com> | |||||
| Rahul Raj <64.rahulraj@gmail.com> | |||||
| @@ -0,0 +1,90 @@ | |||||
| ## 6.3.2 | |||||
| * Updates to Pigeon v22. | |||||
| * Updates minimum supported SDK version to Flutter 3.19/Dart 3.3. | |||||
| ## 6.3.1 | |||||
| * Fixes a compile error when comforming UIApplication to Launcher in iOS 18 Beta 3. | |||||
| ## 6.3.0 | |||||
| * Adds Swift Package Manager compatibility. | |||||
| ## 6.2.5 | |||||
| * Adds explicit imports for UIKit. | |||||
| * Updates minimum iOS version to 12.0 and minimum Flutter version to 3.16.6. | |||||
| ## 6.2.4 | |||||
| * Adds privacy manifest. | |||||
| ## 6.2.3 | |||||
| * Updates minimum required plugin_platform_interface version to 2.1.7. | |||||
| ## 6.2.2 | |||||
| * Updates minimum supported SDK version to Flutter 3.10/Dart 3.0. | |||||
| * Fixes lint warnings. | |||||
| ## 6.2.1 | |||||
| * Migrates plugin from Objective-C to Swift. | |||||
| ## 6.2.0 | |||||
| * Implements `supportsMode` and `supportsCloseForMode`. | |||||
| ## 6.1.5 | |||||
| * Adds pub topics to package metadata. | |||||
| * Updates minimum supported SDK version to Flutter 3.7/Dart 2.19. | |||||
| ## 6.1.4 | |||||
| * Updates pigeon to fix warnings with clang 15. | |||||
| ## 6.1.3 | |||||
| * Switches to Pigeon for internal implementation. | |||||
| ## 6.1.2 | |||||
| * Clarifies explanation of endorsement in README. | |||||
| ## 6.1.1 | |||||
| * Updates links for the merge of flutter/plugins into flutter/packages. | |||||
| ## 6.1.0 | |||||
| * Updates minimum Flutter version to 3.3 and iOS 11. | |||||
| ## 6.0.18 | |||||
| * Updates code for stricter lint checks. | |||||
| * Updates minimum Flutter version to 2.10. | |||||
| ## 6.0.17 | |||||
| * Suppresses warnings for pre-iOS-13 codepaths. | |||||
| ## 6.0.16 | |||||
| * Fixes library_private_types_in_public_api, sort_child_properties_last and use_key_in_widget_constructors | |||||
| lint warnings. | |||||
| ## 6.0.15 | |||||
| * Switches to an in-package method channel implementation. | |||||
| ## 6.0.14 | |||||
| * Updates code for new analysis options. | |||||
| * Removes dependency on `meta`. | |||||
| ## 6.0.13 | |||||
| * Splits from `url_launcher` as a federated implementation. | |||||
| @@ -0,0 +1,25 @@ | |||||
| Copyright 2013 The Flutter 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. | |||||
| @@ -0,0 +1,15 @@ | |||||
| # url\_launcher\_ios | |||||
| The iOS implementation of [`url_launcher`][1]. | |||||
| ## Usage | |||||
| This package is [endorsed][2], which means you can simply use `url_launcher` | |||||
| normally. This package will be automatically included in your app when you do, | |||||
| so you do not need to add it to your `pubspec.yaml`. | |||||
| However, if you `import` this package to use any of its APIs directly, you | |||||
| should add it to your `pubspec.yaml` as usual. | |||||
| [1]: https://pub.dev/packages/url_launcher | |||||
| [2]: https://flutter.dev/to/endorsed-federated-plugin | |||||
| @@ -0,0 +1,9 @@ | |||||
| # Platform Implementation Test App | |||||
| This is a test app for manual testing and automated integration testing | |||||
| of this platform implementation. It is not intended to demonstrate actual use of | |||||
| this package, since the intent is that plugin clients use the app-facing | |||||
| package. | |||||
| Unless you are making changes to this implementation package, this example is | |||||
| very unlikely to be relevant. | |||||
| @@ -0,0 +1,26 @@ | |||||
| // Copyright 2013 The Flutter 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 'package:flutter_test/flutter_test.dart'; | |||||
| import 'package:integration_test/integration_test.dart'; | |||||
| import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; | |||||
| void main() { | |||||
| IntegrationTestWidgetsFlutterBinding.ensureInitialized(); | |||||
| testWidgets('canLaunch', (WidgetTester _) async { | |||||
| final UrlLauncherPlatform launcher = UrlLauncherPlatform.instance; | |||||
| expect(await launcher.canLaunch('randomstring'), false); | |||||
| // Generally all devices should have some default browser. | |||||
| expect(await launcher.canLaunch('http://flutter.dev'), true); | |||||
| // SMS handling is available by default on test devices. | |||||
| expect(await launcher.canLaunch('sms:5555555555'), true); | |||||
| // tel: and mailto: links may not be openable on every device. iOS | |||||
| // simulators notably can't open these link types. | |||||
| }); | |||||
| } | |||||
| @@ -0,0 +1,30 @@ | |||||
| <?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>12.0</string> | |||||
| </dict> | |||||
| </plist> | |||||
| @@ -0,0 +1,2 @@ | |||||
| #include "Generated.xcconfig" | |||||
| #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" | |||||
| @@ -0,0 +1,2 @@ | |||||
| #include "Generated.xcconfig" | |||||
| #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" | |||||
| @@ -0,0 +1,41 @@ | |||||
| # Uncomment this line to define a global platform for your project | |||||
| # platform :ios, '12.0' | |||||
| # CocoaPods analytics sends network stats synchronously affecting flutter build latency. | |||||
| ENV['COCOAPODS_DISABLE_STATS'] = 'true' | |||||
| project 'Runner', { | |||||
| 'Debug' => :debug, | |||||
| 'Profile' => :release, | |||||
| 'Release' => :release, | |||||
| } | |||||
| def flutter_root | |||||
| generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) | |||||
| unless File.exist?(generated_xcode_build_settings_path) | |||||
| raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" | |||||
| end | |||||
| File.foreach(generated_xcode_build_settings_path) do |line| | |||||
| matches = line.match(/FLUTTER_ROOT\=(.*)/) | |||||
| return matches[1].strip if matches | |||||
| end | |||||
| raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" | |||||
| end | |||||
| require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) | |||||
| flutter_ios_podfile_setup | |||||
| target 'Runner' do | |||||
| flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) | |||||
| target 'RunnerTests' do | |||||
| inherit! :search_paths | |||||
| end | |||||
| end | |||||
| post_install do |installer| | |||||
| installer.pods_project.targets.each do |target| | |||||
| flutter_additional_ios_build_settings(target) | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,771 @@ | |||||
| // !$*UTF8*$! | |||||
| { | |||||
| archiveVersion = 1; | |||||
| classes = { | |||||
| }; | |||||
| objectVersion = 54; | |||||
| objects = { | |||||
| /* Begin PBXBuildFile section */ | |||||
| 1D9FF3342A90170000F89C85 /* URLLauncherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D9FF3332A90170000F89C85 /* URLLauncherTests.swift */; }; | |||||
| 1DBE6EDE2A92479000B6525C /* URLLauncherUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DBE6EDD2A92479000B6525C /* URLLauncherUITests.swift */; }; | |||||
| 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 */; }; | |||||
| 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; | |||||
| 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 */; }; | |||||
| B8140773523F70A044426500 /* libPods-RunnerTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 487A1B5A2ECB3E406FD62FE3 /* libPods-RunnerTests.a */; }; | |||||
| /* End PBXBuildFile section */ | |||||
| /* Begin PBXContainerItemProxy section */ | |||||
| F7151F4D26604CFB0028CB91 /* PBXContainerItemProxy */ = { | |||||
| isa = PBXContainerItemProxy; | |||||
| containerPortal = 97C146E61CF9000F007C117D /* Project object */; | |||||
| proxyType = 1; | |||||
| remoteGlobalIDString = 97C146ED1CF9000F007C117D; | |||||
| remoteInfo = Runner; | |||||
| }; | |||||
| F7151F5B26604D060028CB91 /* PBXContainerItemProxy */ = { | |||||
| isa = PBXContainerItemProxy; | |||||
| containerPortal = 97C146E61CF9000F007C117D /* Project object */; | |||||
| proxyType = 1; | |||||
| remoteGlobalIDString = 97C146ED1CF9000F007C117D; | |||||
| remoteInfo = Runner; | |||||
| }; | |||||
| /* End PBXContainerItemProxy section */ | |||||
| /* Begin PBXCopyFilesBuildPhase section */ | |||||
| 9705A1C41CF9048500538489 /* Embed Frameworks */ = { | |||||
| isa = PBXCopyFilesBuildPhase; | |||||
| buildActionMask = 2147483647; | |||||
| dstPath = ""; | |||||
| dstSubfolderSpec = 10; | |||||
| files = ( | |||||
| ); | |||||
| name = "Embed Frameworks"; | |||||
| runOnlyForDeploymentPostprocessing = 0; | |||||
| }; | |||||
| /* End PBXCopyFilesBuildPhase section */ | |||||
| /* Begin PBXFileReference section */ | |||||
| 1D9FF3332A90170000F89C85 /* URLLauncherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLLauncherTests.swift; sourceTree = "<group>"; }; | |||||
| 1DBE6EDD2A92479000B6525C /* URLLauncherUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLLauncherUITests.swift; sourceTree = "<group>"; }; | |||||
| 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>"; }; | |||||
| 487A1B5A2ECB3E406FD62FE3 /* libPods-RunnerTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RunnerTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; | |||||
| 666BCD7C181C34F8BE58929B /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; 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>"; }; | |||||
| 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>"; }; | |||||
| D25C434271ACF6555E002440 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; }; | |||||
| F7151F4826604CFB0028CB91 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; | |||||
| F7151F4C26604CFB0028CB91 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; | |||||
| F7151F5626604D060028CB91 /* RunnerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; | |||||
| F7151F5A26604D060028CB91 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; | |||||
| /* End PBXFileReference section */ | |||||
| /* Begin PBXFrameworksBuildPhase section */ | |||||
| 97C146EB1CF9000F007C117D /* Frameworks */ = { | |||||
| isa = PBXFrameworksBuildPhase; | |||||
| buildActionMask = 2147483647; | |||||
| files = ( | |||||
| 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, | |||||
| 2E37D9A274B2EACB147AC51B /* libPods-Runner.a in Frameworks */, | |||||
| ); | |||||
| runOnlyForDeploymentPostprocessing = 0; | |||||
| }; | |||||
| F7151F4526604CFB0028CB91 /* Frameworks */ = { | |||||
| isa = PBXFrameworksBuildPhase; | |||||
| buildActionMask = 2147483647; | |||||
| files = ( | |||||
| B8140773523F70A044426500 /* libPods-RunnerTests.a in Frameworks */, | |||||
| ); | |||||
| runOnlyForDeploymentPostprocessing = 0; | |||||
| }; | |||||
| F7151F5326604D060028CB91 /* Frameworks */ = { | |||||
| isa = PBXFrameworksBuildPhase; | |||||
| buildActionMask = 2147483647; | |||||
| files = ( | |||||
| ); | |||||
| runOnlyForDeploymentPostprocessing = 0; | |||||
| }; | |||||
| /* End PBXFrameworksBuildPhase section */ | |||||
| /* Begin PBXGroup section */ | |||||
| 840012C8B5EDBCF56B0E4AC1 /* Pods */ = { | |||||
| isa = PBXGroup; | |||||
| children = ( | |||||
| 836316F9AEA584411312E29F /* Pods-Runner.debug.xcconfig */, | |||||
| A84BFEE343F54B983D1B67EB /* Pods-Runner.release.xcconfig */, | |||||
| 666BCD7C181C34F8BE58929B /* Pods-RunnerTests.debug.xcconfig */, | |||||
| D25C434271ACF6555E002440 /* Pods-RunnerTests.release.xcconfig */, | |||||
| ); | |||||
| name = Pods; | |||||
| sourceTree = "<group>"; | |||||
| }; | |||||
| 9740EEB11CF90186004384FC /* Flutter */ = { | |||||
| isa = PBXGroup; | |||||
| children = ( | |||||
| 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, | |||||
| 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 */, | |||||
| F7151F4926604CFB0028CB91 /* RunnerTests */, | |||||
| F7151F5726604D060028CB91 /* RunnerUITests */, | |||||
| 97C146EF1CF9000F007C117D /* Products */, | |||||
| 840012C8B5EDBCF56B0E4AC1 /* Pods */, | |||||
| CF3B75C9A7D2FA2A4C99F110 /* Frameworks */, | |||||
| ); | |||||
| sourceTree = "<group>"; | |||||
| }; | |||||
| 97C146EF1CF9000F007C117D /* Products */ = { | |||||
| isa = PBXGroup; | |||||
| children = ( | |||||
| 97C146EE1CF9000F007C117D /* Runner.app */, | |||||
| F7151F4826604CFB0028CB91 /* RunnerTests.xctest */, | |||||
| F7151F5626604D060028CB91 /* RunnerUITests.xctest */, | |||||
| ); | |||||
| 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 */, | |||||
| 487A1B5A2ECB3E406FD62FE3 /* libPods-RunnerTests.a */, | |||||
| ); | |||||
| name = Frameworks; | |||||
| sourceTree = "<group>"; | |||||
| }; | |||||
| F7151F4926604CFB0028CB91 /* RunnerTests */ = { | |||||
| isa = PBXGroup; | |||||
| children = ( | |||||
| F7151F4C26604CFB0028CB91 /* Info.plist */, | |||||
| 1D9FF3332A90170000F89C85 /* URLLauncherTests.swift */, | |||||
| ); | |||||
| path = RunnerTests; | |||||
| sourceTree = "<group>"; | |||||
| }; | |||||
| F7151F5726604D060028CB91 /* RunnerUITests */ = { | |||||
| isa = PBXGroup; | |||||
| children = ( | |||||
| F7151F5A26604D060028CB91 /* Info.plist */, | |||||
| 1DBE6EDD2A92479000B6525C /* URLLauncherUITests.swift */, | |||||
| ); | |||||
| path = RunnerUITests; | |||||
| 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 */, | |||||
| 3B06AD1E1E4923F5004D2608 /* Thin Binary */, | |||||
| ); | |||||
| buildRules = ( | |||||
| ); | |||||
| dependencies = ( | |||||
| ); | |||||
| name = Runner; | |||||
| packageProductDependencies = ( | |||||
| 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, | |||||
| ); | |||||
| productName = Runner; | |||||
| productReference = 97C146EE1CF9000F007C117D /* Runner.app */; | |||||
| productType = "com.apple.product-type.application"; | |||||
| }; | |||||
| F7151F4726604CFB0028CB91 /* RunnerTests */ = { | |||||
| isa = PBXNativeTarget; | |||||
| buildConfigurationList = F7151F5126604CFB0028CB91 /* Build configuration list for PBXNativeTarget "RunnerTests" */; | |||||
| buildPhases = ( | |||||
| DD4687403C4F35FCD2994FDE /* [CP] Check Pods Manifest.lock */, | |||||
| F7151F4426604CFB0028CB91 /* Sources */, | |||||
| F7151F4526604CFB0028CB91 /* Frameworks */, | |||||
| F7151F4626604CFB0028CB91 /* Resources */, | |||||
| ); | |||||
| buildRules = ( | |||||
| ); | |||||
| dependencies = ( | |||||
| F7151F4E26604CFB0028CB91 /* PBXTargetDependency */, | |||||
| ); | |||||
| name = RunnerTests; | |||||
| productName = RunnerTests; | |||||
| productReference = F7151F4826604CFB0028CB91 /* RunnerTests.xctest */; | |||||
| productType = "com.apple.product-type.bundle.unit-test"; | |||||
| }; | |||||
| F7151F5526604D060028CB91 /* RunnerUITests */ = { | |||||
| isa = PBXNativeTarget; | |||||
| buildConfigurationList = F7151F5D26604D060028CB91 /* Build configuration list for PBXNativeTarget "RunnerUITests" */; | |||||
| buildPhases = ( | |||||
| F7151F5226604D060028CB91 /* Sources */, | |||||
| F7151F5326604D060028CB91 /* Frameworks */, | |||||
| F7151F5426604D060028CB91 /* Resources */, | |||||
| ); | |||||
| buildRules = ( | |||||
| ); | |||||
| dependencies = ( | |||||
| F7151F5C26604D060028CB91 /* PBXTargetDependency */, | |||||
| ); | |||||
| name = RunnerUITests; | |||||
| productName = RunnerUITests; | |||||
| productReference = F7151F5626604D060028CB91 /* RunnerUITests.xctest */; | |||||
| productType = "com.apple.product-type.bundle.ui-testing"; | |||||
| }; | |||||
| /* End PBXNativeTarget section */ | |||||
| /* Begin PBXProject section */ | |||||
| 97C146E61CF9000F007C117D /* Project object */ = { | |||||
| isa = PBXProject; | |||||
| attributes = { | |||||
| LastUpgradeCheck = 1510; | |||||
| ORGANIZATIONNAME = "The Flutter Authors"; | |||||
| TargetAttributes = { | |||||
| 97C146ED1CF9000F007C117D = { | |||||
| CreatedOnToolsVersion = 7.3.1; | |||||
| DevelopmentTeam = S8QB4VV633; | |||||
| }; | |||||
| F7151F4726604CFB0028CB91 = { | |||||
| CreatedOnToolsVersion = 12.5; | |||||
| ProvisioningStyle = Automatic; | |||||
| TestTargetID = 97C146ED1CF9000F007C117D; | |||||
| }; | |||||
| F7151F5526604D060028CB91 = { | |||||
| CreatedOnToolsVersion = 12.5; | |||||
| ProvisioningStyle = Automatic; | |||||
| TestTargetID = 97C146ED1CF9000F007C117D; | |||||
| }; | |||||
| }; | |||||
| }; | |||||
| buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; | |||||
| compatibilityVersion = "Xcode 3.2"; | |||||
| developmentRegion = en; | |||||
| hasScannedForEncodings = 0; | |||||
| knownRegions = ( | |||||
| en, | |||||
| Base, | |||||
| ); | |||||
| mainGroup = 97C146E51CF9000F007C117D; | |||||
| packageReferences = ( | |||||
| 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, | |||||
| ); | |||||
| productRefGroup = 97C146EF1CF9000F007C117D /* Products */; | |||||
| projectDirPath = ""; | |||||
| projectRoot = ""; | |||||
| targets = ( | |||||
| 97C146ED1CF9000F007C117D /* Runner */, | |||||
| F7151F4726604CFB0028CB91 /* RunnerTests */, | |||||
| F7151F5526604D060028CB91 /* RunnerUITests */, | |||||
| ); | |||||
| }; | |||||
| /* 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; | |||||
| }; | |||||
| F7151F4626604CFB0028CB91 /* Resources */ = { | |||||
| isa = PBXResourcesBuildPhase; | |||||
| buildActionMask = 2147483647; | |||||
| files = ( | |||||
| ); | |||||
| runOnlyForDeploymentPostprocessing = 0; | |||||
| }; | |||||
| F7151F5426604D060028CB91 /* Resources */ = { | |||||
| isa = PBXResourcesBuildPhase; | |||||
| buildActionMask = 2147483647; | |||||
| files = ( | |||||
| ); | |||||
| runOnlyForDeploymentPostprocessing = 0; | |||||
| }; | |||||
| /* End PBXResourcesBuildPhase section */ | |||||
| /* Begin PBXShellScriptBuildPhase section */ | |||||
| 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { | |||||
| isa = PBXShellScriptBuildPhase; | |||||
| alwaysOutOfDate = 1; | |||||
| buildActionMask = 2147483647; | |||||
| files = ( | |||||
| ); | |||||
| inputPaths = ( | |||||
| "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", | |||||
| ); | |||||
| name = "Thin Binary"; | |||||
| outputPaths = ( | |||||
| ); | |||||
| runOnlyForDeploymentPostprocessing = 0; | |||||
| shellPath = /bin/sh; | |||||
| shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n"; | |||||
| }; | |||||
| 9740EEB61CF901F6004384FC /* Run Script */ = { | |||||
| isa = PBXShellScriptBuildPhase; | |||||
| alwaysOutOfDate = 1; | |||||
| 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\n"; | |||||
| }; | |||||
| 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; | |||||
| }; | |||||
| DD4687403C4F35FCD2994FDE /* [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-RunnerTests-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; | |||||
| }; | |||||
| F7151F4426604CFB0028CB91 /* Sources */ = { | |||||
| isa = PBXSourcesBuildPhase; | |||||
| buildActionMask = 2147483647; | |||||
| files = ( | |||||
| 1D9FF3342A90170000F89C85 /* URLLauncherTests.swift in Sources */, | |||||
| ); | |||||
| runOnlyForDeploymentPostprocessing = 0; | |||||
| }; | |||||
| F7151F5226604D060028CB91 /* Sources */ = { | |||||
| isa = PBXSourcesBuildPhase; | |||||
| buildActionMask = 2147483647; | |||||
| files = ( | |||||
| 1DBE6EDE2A92479000B6525C /* URLLauncherUITests.swift in Sources */, | |||||
| ); | |||||
| runOnlyForDeploymentPostprocessing = 0; | |||||
| }; | |||||
| /* End PBXSourcesBuildPhase section */ | |||||
| /* Begin PBXTargetDependency section */ | |||||
| F7151F4E26604CFB0028CB91 /* PBXTargetDependency */ = { | |||||
| isa = PBXTargetDependency; | |||||
| target = 97C146ED1CF9000F007C117D /* Runner */; | |||||
| targetProxy = F7151F4D26604CFB0028CB91 /* PBXContainerItemProxy */; | |||||
| }; | |||||
| F7151F5C26604D060028CB91 /* PBXTargetDependency */ = { | |||||
| isa = PBXTargetDependency; | |||||
| target = 97C146ED1CF9000F007C117D /* Runner */; | |||||
| targetProxy = F7151F5B26604D060028CB91 /* PBXContainerItemProxy */; | |||||
| }; | |||||
| /* End PBXTargetDependency 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; | |||||
| 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 = 12.0; | |||||
| MTL_ENABLE_DEBUG_INFO = YES; | |||||
| ONLY_ACTIVE_ARCH = YES; | |||||
| SDKROOT = iphoneos; | |||||
| TARGETED_DEVICE_FAMILY = "1,2"; | |||||
| }; | |||||
| name = Debug; | |||||
| }; | |||||
| 97C147041CF9000F007C117D /* Release */ = { | |||||
| isa = XCBuildConfiguration; | |||||
| 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 = 12.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 = dev.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 = dev.flutter.plugins.urlLauncher; | |||||
| PRODUCT_NAME = "$(TARGET_NAME)"; | |||||
| }; | |||||
| name = Release; | |||||
| }; | |||||
| F7151F4F26604CFB0028CB91 /* Debug */ = { | |||||
| isa = XCBuildConfiguration; | |||||
| baseConfigurationReference = 666BCD7C181C34F8BE58929B /* Pods-RunnerTests.debug.xcconfig */; | |||||
| buildSettings = { | |||||
| BUNDLE_LOADER = "$(TEST_HOST)"; | |||||
| CLANG_ENABLE_MODULES = YES; | |||||
| CODE_SIGN_STYLE = Automatic; | |||||
| INFOPLIST_FILE = RunnerTests/Info.plist; | |||||
| LD_RUNPATH_SEARCH_PATHS = ( | |||||
| "$(inherited)", | |||||
| "@executable_path/Frameworks", | |||||
| "@loader_path/Frameworks", | |||||
| ); | |||||
| MTL_FAST_MATH = YES; | |||||
| PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerTests; | |||||
| PRODUCT_NAME = "$(TARGET_NAME)"; | |||||
| SWIFT_VERSION = 5.0; | |||||
| TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner"; | |||||
| }; | |||||
| name = Debug; | |||||
| }; | |||||
| F7151F5026604CFB0028CB91 /* Release */ = { | |||||
| isa = XCBuildConfiguration; | |||||
| baseConfigurationReference = D25C434271ACF6555E002440 /* Pods-RunnerTests.release.xcconfig */; | |||||
| buildSettings = { | |||||
| BUNDLE_LOADER = "$(TEST_HOST)"; | |||||
| CLANG_ENABLE_MODULES = YES; | |||||
| CODE_SIGN_STYLE = Automatic; | |||||
| INFOPLIST_FILE = RunnerTests/Info.plist; | |||||
| LD_RUNPATH_SEARCH_PATHS = ( | |||||
| "$(inherited)", | |||||
| "@executable_path/Frameworks", | |||||
| "@loader_path/Frameworks", | |||||
| ); | |||||
| MTL_FAST_MATH = YES; | |||||
| PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerTests; | |||||
| PRODUCT_NAME = "$(TARGET_NAME)"; | |||||
| SWIFT_VERSION = 5.0; | |||||
| TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner"; | |||||
| }; | |||||
| name = Release; | |||||
| }; | |||||
| F7151F5E26604D060028CB91 /* Debug */ = { | |||||
| isa = XCBuildConfiguration; | |||||
| buildSettings = { | |||||
| CODE_SIGN_STYLE = Automatic; | |||||
| INFOPLIST_FILE = RunnerUITests/Info.plist; | |||||
| LD_RUNPATH_SEARCH_PATHS = ( | |||||
| "$(inherited)", | |||||
| "@executable_path/Frameworks", | |||||
| "@loader_path/Frameworks", | |||||
| ); | |||||
| MTL_FAST_MATH = YES; | |||||
| PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerUITests; | |||||
| PRODUCT_NAME = "$(TARGET_NAME)"; | |||||
| SWIFT_VERSION = 5.0; | |||||
| TEST_TARGET_NAME = Runner; | |||||
| }; | |||||
| name = Debug; | |||||
| }; | |||||
| F7151F5F26604D060028CB91 /* Release */ = { | |||||
| isa = XCBuildConfiguration; | |||||
| buildSettings = { | |||||
| CODE_SIGN_STYLE = Automatic; | |||||
| INFOPLIST_FILE = RunnerUITests/Info.plist; | |||||
| LD_RUNPATH_SEARCH_PATHS = ( | |||||
| "$(inherited)", | |||||
| "@executable_path/Frameworks", | |||||
| "@loader_path/Frameworks", | |||||
| ); | |||||
| MTL_FAST_MATH = YES; | |||||
| PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerUITests; | |||||
| PRODUCT_NAME = "$(TARGET_NAME)"; | |||||
| SWIFT_VERSION = 5.0; | |||||
| TEST_TARGET_NAME = Runner; | |||||
| }; | |||||
| 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; | |||||
| }; | |||||
| F7151F5126604CFB0028CB91 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { | |||||
| isa = XCConfigurationList; | |||||
| buildConfigurations = ( | |||||
| F7151F4F26604CFB0028CB91 /* Debug */, | |||||
| F7151F5026604CFB0028CB91 /* Release */, | |||||
| ); | |||||
| defaultConfigurationIsVisible = 0; | |||||
| defaultConfigurationName = Release; | |||||
| }; | |||||
| F7151F5D26604D060028CB91 /* Build configuration list for PBXNativeTarget "RunnerUITests" */ = { | |||||
| isa = XCConfigurationList; | |||||
| buildConfigurations = ( | |||||
| F7151F5E26604D060028CB91 /* Debug */, | |||||
| F7151F5F26604D060028CB91 /* Release */, | |||||
| ); | |||||
| defaultConfigurationIsVisible = 0; | |||||
| defaultConfigurationName = Release; | |||||
| }; | |||||
| /* End XCConfigurationList section */ | |||||
| /* Begin XCLocalSwiftPackageReference section */ | |||||
| 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { | |||||
| isa = XCLocalSwiftPackageReference; | |||||
| relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; | |||||
| }; | |||||
| /* End XCLocalSwiftPackageReference section */ | |||||
| /* Begin XCSwiftPackageProductDependency section */ | |||||
| 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { | |||||
| isa = XCSwiftPackageProductDependency; | |||||
| productName = FlutterGeneratedPluginSwiftPackage; | |||||
| }; | |||||
| /* End XCSwiftPackageProductDependency section */ | |||||
| }; | |||||
| rootObject = 97C146E61CF9000F007C117D /* Project object */; | |||||
| } | |||||
| @@ -0,0 +1,7 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <Workspace | |||||
| version = "1.0"> | |||||
| <FileRef | |||||
| location = "self:"> | |||||
| </FileRef> | |||||
| </Workspace> | |||||
| @@ -0,0 +1,126 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <Scheme | |||||
| LastUpgradeVersion = "1510" | |||||
| version = "1.3"> | |||||
| <BuildAction | |||||
| parallelizeBuildables = "YES" | |||||
| buildImplicitDependencies = "YES"> | |||||
| <PreActions> | |||||
| <ExecutionAction | |||||
| ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction"> | |||||
| <ActionContent | |||||
| title = "Run Prepare Flutter Framework Script" | |||||
| scriptText = "/bin/sh "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" prepare "> | |||||
| <EnvironmentBuildable> | |||||
| <BuildableReference | |||||
| BuildableIdentifier = "primary" | |||||
| BlueprintIdentifier = "97C146ED1CF9000F007C117D" | |||||
| BuildableName = "Runner.app" | |||||
| BlueprintName = "Runner" | |||||
| ReferencedContainer = "container:Runner.xcodeproj"> | |||||
| </BuildableReference> | |||||
| </EnvironmentBuildable> | |||||
| </ActionContent> | |||||
| </ExecutionAction> | |||||
| </PreActions> | |||||
| <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> | |||||
| <TestableReference | |||||
| skipped = "NO"> | |||||
| <BuildableReference | |||||
| BuildableIdentifier = "primary" | |||||
| BlueprintIdentifier = "F7151F4726604CFB0028CB91" | |||||
| BuildableName = "RunnerTests.xctest" | |||||
| BlueprintName = "RunnerTests" | |||||
| ReferencedContainer = "container:Runner.xcodeproj"> | |||||
| </BuildableReference> | |||||
| </TestableReference> | |||||
| <TestableReference | |||||
| skipped = "NO"> | |||||
| <BuildableReference | |||||
| BuildableIdentifier = "primary" | |||||
| BlueprintIdentifier = "F7151F5526604D060028CB91" | |||||
| BuildableName = "RunnerUITests.xctest" | |||||
| BlueprintName = "RunnerUITests" | |||||
| ReferencedContainer = "container:Runner.xcodeproj"> | |||||
| </BuildableReference> | |||||
| </TestableReference> | |||||
| </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" | |||||
| enableGPUValidationMode = "1" | |||||
| 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> | |||||
| @@ -0,0 +1,10 @@ | |||||
| <?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> | |||||
| @@ -0,0 +1,8 @@ | |||||
| <?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> | |||||
| @@ -0,0 +1,10 @@ | |||||
| // Copyright 2013 The Flutter 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 | |||||
| @@ -0,0 +1,17 @@ | |||||
| // Copyright 2013 The Flutter 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 | |||||
| @@ -0,0 +1,116 @@ | |||||
| { | |||||
| "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" | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,27 @@ | |||||
| <?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> | |||||
| @@ -0,0 +1,26 @@ | |||||
| <?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> | |||||
| @@ -0,0 +1,51 @@ | |||||
| <?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>CADisableMinimumFrameDurationOnPhone</key> | |||||
| <true/> | |||||
| <key>UIApplicationSupportsIndirectInputEvents</key> | |||||
| <true/> | |||||
| </dict> | |||||
| </plist> | |||||
| @@ -0,0 +1,13 @@ | |||||
| // Copyright 2013 The Flutter 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])); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,22 @@ | |||||
| <?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>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>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string> | |||||
| <key>CFBundleShortVersionString</key> | |||||
| <string>1.0</string> | |||||
| <key>CFBundleVersion</key> | |||||
| <string>1</string> | |||||
| </dict> | |||||
| </plist> | |||||
| @@ -0,0 +1,151 @@ | |||||
| // Copyright 2013 The Flutter 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 | |||||
| import XCTest | |||||
| @testable import url_launcher_ios | |||||
| // Tests whether NSURL parsing is strict. When linking against the iOS 17 SDK or later, | |||||
| // NSURL uses a more lenient parser which will not return nil. | |||||
| private func urlParsingIsStrict() -> Bool { | |||||
| return URL(string: "b a d U R L") == nil | |||||
| } | |||||
| final class URLLauncherTests: XCTestCase { | |||||
| private func createPlugin() -> URLLauncherPlugin { | |||||
| let launcher = FakeLauncher() | |||||
| return URLLauncherPlugin(launcher: launcher) | |||||
| } | |||||
| private func createPlugin(launcher: FakeLauncher) -> URLLauncherPlugin { | |||||
| return URLLauncherPlugin(launcher: launcher) | |||||
| } | |||||
| func testCanLaunchSuccess() { | |||||
| let result = createPlugin().canLaunchUrl(url: "good://url") | |||||
| XCTAssertEqual(result, .success) | |||||
| } | |||||
| func testCanLaunchFailure() { | |||||
| let result = createPlugin().canLaunchUrl(url: "bad://url") | |||||
| XCTAssertEqual(result, .failure) | |||||
| } | |||||
| func testCanLaunchFailureWithInvalidURL() { | |||||
| let result = createPlugin().canLaunchUrl(url: "urls can't have spaces") | |||||
| if urlParsingIsStrict() { | |||||
| XCTAssertEqual(result, .invalidUrl) | |||||
| } else { | |||||
| XCTAssertEqual(result, .failure) | |||||
| } | |||||
| } | |||||
| func testLaunchSuccess() { | |||||
| let expectation = XCTestExpectation(description: "completion called") | |||||
| createPlugin().launchUrl(url: "good://url", universalLinksOnly: false) { result in | |||||
| switch result { | |||||
| case .success(let details): | |||||
| XCTAssertEqual(details, .success) | |||||
| case .failure(let error): | |||||
| XCTFail("Unexpected error: \(error)") | |||||
| } | |||||
| expectation.fulfill() | |||||
| } | |||||
| wait(for: [expectation], timeout: 1) | |||||
| } | |||||
| func testLaunchFailure() { | |||||
| let expectation = XCTestExpectation(description: "completion called") | |||||
| createPlugin().launchUrl(url: "bad://url", universalLinksOnly: false) { result in | |||||
| switch result { | |||||
| case .success(let details): | |||||
| XCTAssertEqual(details, .failure) | |||||
| case .failure(let error): | |||||
| XCTFail("Unexpected error: \(error)") | |||||
| } | |||||
| expectation.fulfill() | |||||
| } | |||||
| wait(for: [expectation], timeout: 1) | |||||
| } | |||||
| func testLaunchFailureWithInvalidURL() { | |||||
| let expectation = XCTestExpectation(description: "completion called") | |||||
| createPlugin().launchUrl(url: "urls can't have spaces", universalLinksOnly: false) { result in | |||||
| switch result { | |||||
| case .success(let details): | |||||
| if urlParsingIsStrict() { | |||||
| XCTAssertEqual(details, .invalidUrl) | |||||
| } else { | |||||
| XCTAssertEqual(details, .failure) | |||||
| } | |||||
| case .failure(let error): | |||||
| XCTFail("Unexpected error: \(error)") | |||||
| } | |||||
| expectation.fulfill() | |||||
| } | |||||
| wait(for: [expectation], timeout: 1) | |||||
| } | |||||
| func testLaunchWithoutUniversalLinks() { | |||||
| let launcher = FakeLauncher() | |||||
| let plugin = createPlugin(launcher: launcher) | |||||
| let expectation = XCTestExpectation(description: "completion called") | |||||
| plugin.launchUrl(url: "good://url", universalLinksOnly: false) { result in | |||||
| switch result { | |||||
| case .success(let details): | |||||
| XCTAssertEqual(details, .success) | |||||
| case .failure(let error): | |||||
| XCTFail("Unexpected error: \(error)") | |||||
| } | |||||
| expectation.fulfill() | |||||
| } | |||||
| wait(for: [expectation], timeout: 1) | |||||
| XCTAssertEqual(launcher.passedOptions?[.universalLinksOnly] as? Bool, false) | |||||
| } | |||||
| func testLaunchWithUniversalLinks() { | |||||
| let launcher = FakeLauncher() | |||||
| let plugin = createPlugin(launcher: launcher) | |||||
| let expectation = XCTestExpectation(description: "completion called") | |||||
| plugin.launchUrl(url: "good://url", universalLinksOnly: true) { result in | |||||
| switch result { | |||||
| case .success(let details): | |||||
| XCTAssertEqual(details, .success) | |||||
| case .failure(let error): | |||||
| XCTFail("Unexpected error: \(error)") | |||||
| } | |||||
| expectation.fulfill() | |||||
| } | |||||
| wait(for: [expectation], timeout: 1) | |||||
| XCTAssertEqual(launcher.passedOptions?[.universalLinksOnly] as? Bool, true) | |||||
| } | |||||
| } | |||||
| final private class FakeLauncher: NSObject, Launcher { | |||||
| var passedOptions: [UIApplication.OpenExternalURLOptionsKey: Any]? | |||||
| func canOpenURL(_ url: URL) -> Bool { | |||||
| url.scheme == "good" | |||||
| } | |||||
| func open( | |||||
| _ url: URL, | |||||
| options: [UIApplication.OpenExternalURLOptionsKey: Any], | |||||
| completionHandler completion: ((Bool) -> Void)? | |||||
| ) { | |||||
| self.passedOptions = options | |||||
| completion?(url.scheme == "good") | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,22 @@ | |||||
| <?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>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>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string> | |||||
| <key>CFBundleShortVersionString</key> | |||||
| <string>1.0</string> | |||||
| <key>CFBundleVersion</key> | |||||
| <string>1</string> | |||||
| </dict> | |||||
| </plist> | |||||
| @@ -0,0 +1,42 @@ | |||||
| // Copyright 2013 The Flutter 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 XCTest | |||||
| class URLLauncherUITests: XCTestCase { | |||||
| var app: XCUIApplication! | |||||
| override func setUp() { | |||||
| continueAfterFailure = false | |||||
| app = XCUIApplication() | |||||
| app.launch() | |||||
| } | |||||
| func testLaunch() { | |||||
| let app = self.app! | |||||
| let buttonNames: [String] = [ | |||||
| "Launch in app", "Launch in app(JavaScript ON)", "Launch in app(DOM storage ON)", | |||||
| "Launch a universal link in a native app, fallback to Safari.(Youtube)", | |||||
| ] | |||||
| for buttonName in buttonNames { | |||||
| let button = app.buttons[buttonName] | |||||
| XCTAssertTrue(button.waitForExistence(timeout: 30.0)) | |||||
| XCTAssertEqual(app.webViews.count, 0) | |||||
| button.tap() | |||||
| let webView = app.webViews.firstMatch | |||||
| XCTAssertTrue(webView.waitForExistence(timeout: 30.0)) | |||||
| XCTAssertTrue(app.buttons["ForwardButton"].waitForExistence(timeout: 30.0)) | |||||
| XCTAssertTrue(app.buttons["Share"].exists) | |||||
| XCTAssertTrue(app.buttons["OpenInSafariButton"].exists) | |||||
| let doneButton = app.buttons["Done"] | |||||
| XCTAssertTrue(doneButton.waitForExistence(timeout: 30.0)) | |||||
| // This should just be doneButton.tap, but for some reason that stopped working in Xcode 15; | |||||
| // tapping via coordinate works, however. | |||||
| doneButton.coordinate(withNormalizedOffset: CGVector()).withOffset(CGVector(dx: 10, dy: 10)) | |||||
| .tap() | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,242 @@ | |||||
| // Copyright 2013 The Flutter 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_platform_interface/url_launcher_platform_interface.dart'; | |||||
| void main() { | |||||
| runApp(const MyApp()); | |||||
| } | |||||
| class MyApp extends StatelessWidget { | |||||
| const MyApp({super.key}); | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return MaterialApp( | |||||
| title: 'URL Launcher', | |||||
| theme: ThemeData( | |||||
| primarySwatch: Colors.blue, | |||||
| ), | |||||
| home: const MyHomePage(title: 'URL Launcher'), | |||||
| ); | |||||
| } | |||||
| } | |||||
| class MyHomePage extends StatefulWidget { | |||||
| const MyHomePage({super.key, required this.title}); | |||||
| final String title; | |||||
| @override | |||||
| State<MyHomePage> createState() => _MyHomePageState(); | |||||
| } | |||||
| class _MyHomePageState extends State<MyHomePage> { | |||||
| Future<void>? _launched; | |||||
| String _phone = ''; | |||||
| Future<void> _launchInBrowser(String url) async { | |||||
| final UrlLauncherPlatform launcher = UrlLauncherPlatform.instance; | |||||
| if (await launcher.canLaunch(url)) { | |||||
| await launcher.launch( | |||||
| url, | |||||
| useSafariVC: false, | |||||
| useWebView: false, | |||||
| enableJavaScript: false, | |||||
| enableDomStorage: false, | |||||
| universalLinksOnly: false, | |||||
| headers: <String, String>{'my_header_key': 'my_header_value'}, | |||||
| ); | |||||
| } else { | |||||
| throw Exception('Could not launch $url'); | |||||
| } | |||||
| } | |||||
| Future<void> _launchInWebViewOrVC(String url) async { | |||||
| final UrlLauncherPlatform launcher = UrlLauncherPlatform.instance; | |||||
| if (await launcher.canLaunch(url)) { | |||||
| await launcher.launch( | |||||
| url, | |||||
| useSafariVC: true, | |||||
| useWebView: true, | |||||
| enableJavaScript: false, | |||||
| enableDomStorage: false, | |||||
| universalLinksOnly: false, | |||||
| headers: <String, String>{'my_header_key': 'my_header_value'}, | |||||
| ); | |||||
| } else { | |||||
| throw Exception('Could not launch $url'); | |||||
| } | |||||
| } | |||||
| Future<void> _launchInWebViewWithJavaScript(String url) async { | |||||
| final UrlLauncherPlatform launcher = UrlLauncherPlatform.instance; | |||||
| if (await launcher.canLaunch(url)) { | |||||
| await launcher.launch( | |||||
| url, | |||||
| useSafariVC: true, | |||||
| useWebView: true, | |||||
| enableJavaScript: true, | |||||
| enableDomStorage: false, | |||||
| universalLinksOnly: false, | |||||
| headers: <String, String>{}, | |||||
| ); | |||||
| } else { | |||||
| throw Exception('Could not launch $url'); | |||||
| } | |||||
| } | |||||
| Future<void> _launchInWebViewWithDomStorage(String url) async { | |||||
| final UrlLauncherPlatform launcher = UrlLauncherPlatform.instance; | |||||
| if (await launcher.canLaunch(url)) { | |||||
| await launcher.launch( | |||||
| url, | |||||
| useSafariVC: true, | |||||
| useWebView: true, | |||||
| enableJavaScript: false, | |||||
| enableDomStorage: true, | |||||
| universalLinksOnly: false, | |||||
| headers: <String, String>{}, | |||||
| ); | |||||
| } else { | |||||
| throw Exception('Could not launch $url'); | |||||
| } | |||||
| } | |||||
| Future<void> _launchUniversalLinkIos(String url) async { | |||||
| final UrlLauncherPlatform launcher = UrlLauncherPlatform.instance; | |||||
| if (await launcher.canLaunch(url)) { | |||||
| final bool nativeAppLaunchSucceeded = await launcher.launch( | |||||
| url, | |||||
| useSafariVC: false, | |||||
| useWebView: false, | |||||
| enableJavaScript: false, | |||||
| enableDomStorage: false, | |||||
| universalLinksOnly: true, | |||||
| headers: <String, String>{}, | |||||
| ); | |||||
| if (!nativeAppLaunchSucceeded) { | |||||
| await launcher.launch( | |||||
| url, | |||||
| useSafariVC: true, | |||||
| useWebView: true, | |||||
| enableJavaScript: false, | |||||
| enableDomStorage: false, | |||||
| universalLinksOnly: true, | |||||
| headers: <String, String>{}, | |||||
| ); | |||||
| } | |||||
| } | |||||
| } | |||||
| 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 { | |||||
| final UrlLauncherPlatform launcher = UrlLauncherPlatform.instance; | |||||
| if (await launcher.canLaunch(url)) { | |||||
| await launcher.launch( | |||||
| url, | |||||
| useSafariVC: false, | |||||
| useWebView: false, | |||||
| enableJavaScript: false, | |||||
| enableDomStorage: false, | |||||
| universalLinksOnly: true, | |||||
| headers: <String, String>{}, | |||||
| ); | |||||
| } else { | |||||
| throw Exception('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')), | |||||
| ), | |||||
| ElevatedButton( | |||||
| onPressed: () => setState(() { | |||||
| _launched = _makePhoneCall('tel:$_phone'); | |||||
| }), | |||||
| child: const Text('Make phone call'), | |||||
| ), | |||||
| const Padding( | |||||
| padding: EdgeInsets.all(16.0), | |||||
| child: Text(toLaunch), | |||||
| ), | |||||
| ElevatedButton( | |||||
| onPressed: () => setState(() { | |||||
| _launched = _launchInBrowser(toLaunch); | |||||
| }), | |||||
| child: const Text('Launch in browser'), | |||||
| ), | |||||
| const Padding(padding: EdgeInsets.all(16.0)), | |||||
| ElevatedButton( | |||||
| onPressed: () => setState(() { | |||||
| _launched = _launchInWebViewOrVC(toLaunch); | |||||
| }), | |||||
| child: const Text('Launch in app'), | |||||
| ), | |||||
| ElevatedButton( | |||||
| onPressed: () => setState(() { | |||||
| _launched = _launchInWebViewWithJavaScript(toLaunch); | |||||
| }), | |||||
| child: const Text('Launch in app(JavaScript ON)'), | |||||
| ), | |||||
| ElevatedButton( | |||||
| onPressed: () => setState(() { | |||||
| _launched = _launchInWebViewWithDomStorage(toLaunch); | |||||
| }), | |||||
| child: const Text('Launch in app(DOM storage ON)'), | |||||
| ), | |||||
| const Padding(padding: EdgeInsets.all(16.0)), | |||||
| ElevatedButton( | |||||
| 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)), | |||||
| ElevatedButton( | |||||
| onPressed: () => setState(() { | |||||
| _launched = _launchInWebViewOrVC(toLaunch); | |||||
| Timer(const Duration(seconds: 5), () { | |||||
| UrlLauncherPlatform.instance.closeWebView(); | |||||
| }); | |||||
| }), | |||||
| child: const Text('Launch in app + close after 5 seconds'), | |||||
| ), | |||||
| const Padding(padding: EdgeInsets.all(16.0)), | |||||
| FutureBuilder<void>(future: _launched, builder: _launchStatus), | |||||
| ], | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,29 @@ | |||||
| name: url_launcher_example | |||||
| description: Demonstrates how to use the url_launcher plugin. | |||||
| publish_to: none | |||||
| environment: | |||||
| sdk: ^3.3.0 | |||||
| flutter: ">=3.19.0" | |||||
| dependencies: | |||||
| flutter: | |||||
| sdk: flutter | |||||
| url_launcher_ios: | |||||
| # When depending on this package from a real application you should use: | |||||
| # url_launcher_ios: ^x.y.z | |||||
| # See https://dart.dev/tools/pub/dependencies#version-constraints | |||||
| # The example app is bundled with the plugin so we use a path dependency on | |||||
| # the parent directory to use the current plugin's version. | |||||
| path: ../ | |||||
| url_launcher_platform_interface: ^2.2.0 | |||||
| dev_dependencies: | |||||
| flutter_test: | |||||
| sdk: flutter | |||||
| integration_test: | |||||
| sdk: flutter | |||||
| plugin_platform_interface: ^2.1.7 | |||||
| flutter: | |||||
| uses-material-design: true | |||||
| @@ -0,0 +1,7 @@ | |||||
| // Copyright 2013 The Flutter 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 'package:integration_test/integration_test_driver.dart'; | |||||
| Future<void> main() => integrationDriver(); | |||||
| @@ -0,0 +1,26 @@ | |||||
| # | |||||
| # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html | |||||
| # | |||||
| Pod::Spec.new do |s| | |||||
| s.name = 'url_launcher_ios' | |||||
| 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/packages/tree/main/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/packages/tree/main/packages/url_launcher/url_launcher_ios' } | |||||
| s.documentation_url = 'https://pub.dev/packages/url_launcher' | |||||
| s.swift_version = '5.0' | |||||
| s.source_files = 'url_launcher_ios/Sources/**/*.swift' | |||||
| s.xcconfig = { | |||||
| 'LIBRARY_SEARCH_PATHS' => '$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)/ $(SDKROOT)/usr/lib/swift', | |||||
| 'LD_RUNPATH_SEARCH_PATHS' => '/usr/lib/swift', | |||||
| } | |||||
| s.dependency 'Flutter' | |||||
| s.platform = :ios, '12.0' | |||||
| s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } | |||||
| s.resource_bundles = {'url_launcher_ios_privacy' => ['url_launcher_ios/Sources/url_launcher_ios/Resources/PrivacyInfo.xcprivacy']} | |||||
| end | |||||
| @@ -0,0 +1,28 @@ | |||||
| // swift-tools-version: 5.9 | |||||
| // The swift-tools-version declares the minimum version of Swift required to build this package. | |||||
| // Copyright 2013 The Flutter 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 PackageDescription | |||||
| let package = Package( | |||||
| name: "url_launcher_ios", | |||||
| platforms: [ | |||||
| .iOS("12.0") | |||||
| ], | |||||
| products: [ | |||||
| .library(name: "url-launcher-ios", targets: ["url_launcher_ios"]) | |||||
| ], | |||||
| dependencies: [], | |||||
| targets: [ | |||||
| .target( | |||||
| name: "url_launcher_ios", | |||||
| dependencies: [], | |||||
| resources: [ | |||||
| .process("Resources") | |||||
| ] | |||||
| ) | |||||
| ] | |||||
| ) | |||||
| @@ -0,0 +1,38 @@ | |||||
| // Copyright 2013 The Flutter 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 UIKit | |||||
| /// Protocol for UIApplication methods relating to launching URLs. | |||||
| /// | |||||
| /// This protocol exists to allow injecting an alternate implementation for testing. | |||||
| protocol Launcher { | |||||
| /// Returns a Boolean value that indicates whether an app is available to handle a URL scheme. | |||||
| func canOpenURL(_ url: URL) -> Bool | |||||
| /// Attempts to asynchronously open the resource at the specified URL. | |||||
| func open( | |||||
| _ url: URL, | |||||
| options: [UIApplication.OpenExternalURLOptionsKey: Any], | |||||
| completionHandler completion: ((Bool) -> Void)?) | |||||
| } | |||||
| // TODO(hellohuanlin): This wrapper is a workaround for iOS 18 Beta 3 where completionHandler is annotated with @MainActor @Sendable, resulting in compile error when conforming UIApplication to Launcher. We should try again in newer betas. | |||||
| /// A default URL launcher. | |||||
| final class DefaultLauncher: Launcher { | |||||
| func canOpenURL(_ url: URL) -> Bool { | |||||
| return UIApplication.shared.canOpenURL(url) | |||||
| } | |||||
| func open( | |||||
| _ url: URL, | |||||
| options: [UIApplication.OpenExternalURLOptionsKey: Any], | |||||
| completionHandler completion: ((Bool) -> Void)? | |||||
| ) { | |||||
| UIApplication.shared.open( | |||||
| url, | |||||
| options: options, | |||||
| completionHandler: completion) | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,14 @@ | |||||
| <?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>NSPrivacyTrackingDomains</key> | |||||
| <array/> | |||||
| <key>NSPrivacyAccessedAPITypes</key> | |||||
| <array/> | |||||
| <key>NSPrivacyCollectedDataTypes</key> | |||||
| <array/> | |||||
| <key>NSPrivacyTracking</key> | |||||
| <false/> | |||||
| </dict> | |||||
| </plist> | |||||
| @@ -0,0 +1,63 @@ | |||||
| // Copyright 2013 The Flutter 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 | |||||
| import SafariServices | |||||
| typealias OpenInSafariCompletionHandler = (Result<InAppLoadResult, Error>) -> Void | |||||
| /// A session responsible for launching a URL in Safari and handling its events. | |||||
| final class URLLaunchSession: NSObject, SFSafariViewControllerDelegate { | |||||
| private let completion: OpenInSafariCompletionHandler | |||||
| private let url: URL | |||||
| /// The Safari view controller used for displaying the URL. | |||||
| let safariViewController: SFSafariViewController | |||||
| // A closure to be executed after the Safari view controller finishes. | |||||
| var didFinish: (() -> Void)? | |||||
| /// Initializes a new URLLaunchSession with the provided URL and completion handler. | |||||
| /// | |||||
| /// - Parameters: | |||||
| /// - url: The URL to be opened in Safari. | |||||
| /// - completion: The completion handler to be called after attempting to open the URL. | |||||
| init(url: URL, completion: @escaping OpenInSafariCompletionHandler) { | |||||
| self.url = url | |||||
| self.completion = completion | |||||
| self.safariViewController = SFSafariViewController(url: url) | |||||
| super.init() | |||||
| self.safariViewController.delegate = self | |||||
| } | |||||
| /// Called when the Safari view controller completes the initial load. | |||||
| /// | |||||
| /// - Parameters: | |||||
| /// - controller: The Safari view controller. | |||||
| /// - didLoadSuccessfully: Indicates if the initial load was successful. | |||||
| func safariViewController( | |||||
| _ controller: SFSafariViewController, | |||||
| didCompleteInitialLoad didLoadSuccessfully: Bool | |||||
| ) { | |||||
| if didLoadSuccessfully { | |||||
| completion(.success(.success)) | |||||
| } else { | |||||
| completion(.success(.failedToLoad)) | |||||
| } | |||||
| } | |||||
| /// Called when the user finishes using the Safari view controller. | |||||
| /// | |||||
| /// - Parameter controller: The Safari view controller. | |||||
| func safariViewControllerDidFinish(_ controller: SFSafariViewController) { | |||||
| controller.dismiss(animated: true, completion: nil) | |||||
| didFinish?() | |||||
| } | |||||
| /// Closes the Safari view controller. | |||||
| func close() { | |||||
| safariViewControllerDidFinish(safariViewController) | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,100 @@ | |||||
| // Copyright 2013 The Flutter 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 | |||||
| import UIKit | |||||
| public final class URLLauncherPlugin: NSObject, FlutterPlugin, UrlLauncherApi { | |||||
| public static func register(with registrar: FlutterPluginRegistrar) { | |||||
| let plugin = URLLauncherPlugin() | |||||
| UrlLauncherApiSetup.setUp(binaryMessenger: registrar.messenger(), api: plugin) | |||||
| registrar.publish(plugin) | |||||
| } | |||||
| private var currentSession: URLLaunchSession? | |||||
| private let launcher: Launcher | |||||
| private var topViewController: UIViewController? { | |||||
| // TODO(stuartmorgan) Provide a non-deprecated codepath. See | |||||
| // https://github.com/flutter/flutter/issues/104117 | |||||
| UIApplication.shared.keyWindow?.rootViewController?.topViewController | |||||
| } | |||||
| init(launcher: Launcher = DefaultLauncher()) { | |||||
| self.launcher = launcher | |||||
| } | |||||
| func canLaunchUrl(url: String) -> LaunchResult { | |||||
| guard let url = URL(string: url) else { | |||||
| return .invalidUrl | |||||
| } | |||||
| let canOpen = launcher.canOpenURL(url) | |||||
| return canOpen ? .success : .failure | |||||
| } | |||||
| func launchUrl( | |||||
| url: String, | |||||
| universalLinksOnly: Bool, | |||||
| completion: @escaping (Result<LaunchResult, Error>) -> Void | |||||
| ) { | |||||
| guard let url = URL(string: url) else { | |||||
| completion(.success(.invalidUrl)) | |||||
| return | |||||
| } | |||||
| let options = [UIApplication.OpenExternalURLOptionsKey.universalLinksOnly: universalLinksOnly] | |||||
| launcher.open(url, options: options) { result in | |||||
| completion(.success(result ? .success : .failure)) | |||||
| } | |||||
| } | |||||
| func openUrlInSafariViewController( | |||||
| url: String, | |||||
| completion: @escaping (Result<InAppLoadResult, Error>) -> Void | |||||
| ) { | |||||
| guard let url = URL(string: url) else { | |||||
| completion(.success(.invalidUrl)) | |||||
| return | |||||
| } | |||||
| let session = URLLaunchSession(url: url, completion: completion) | |||||
| currentSession = session | |||||
| session.didFinish = { [weak self] in | |||||
| self?.currentSession = nil | |||||
| } | |||||
| topViewController?.present(session.safariViewController, animated: true, completion: nil) | |||||
| } | |||||
| func closeSafariViewController() { | |||||
| currentSession?.close() | |||||
| } | |||||
| } | |||||
| /// This method recursively iterates 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. | |||||
| extension UIViewController { | |||||
| var topViewController: UIViewController { | |||||
| if let navigationController = self as? UINavigationController { | |||||
| return navigationController.viewControllers.last?.topViewController | |||||
| ?? navigationController | |||||
| .visibleViewController ?? navigationController | |||||
| } | |||||
| if let tabBarController = self as? UITabBarController { | |||||
| return tabBarController.selectedViewController?.topViewController ?? tabBarController | |||||
| } | |||||
| if let presented = presentedViewController { | |||||
| return presented.topViewController | |||||
| } | |||||
| return self | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,242 @@ | |||||
| // Copyright 2013 The Flutter Authors. All rights reserved. | |||||
| // Use of this source code is governed by a BSD-style license that can be | |||||
| // found in the LICENSE file. | |||||
| // Autogenerated from Pigeon (v22.6.4), do not edit directly. | |||||
| // See also: https://pub.dev/packages/pigeon | |||||
| import Foundation | |||||
| #if os(iOS) | |||||
| import Flutter | |||||
| #elseif os(macOS) | |||||
| import FlutterMacOS | |||||
| #else | |||||
| #error("Unsupported platform.") | |||||
| #endif | |||||
| /// Error class for passing custom error details to Dart side. | |||||
| final class PigeonError: Error { | |||||
| let code: String | |||||
| let message: String? | |||||
| let details: Any? | |||||
| init(code: String, message: String?, details: Any?) { | |||||
| self.code = code | |||||
| self.message = message | |||||
| self.details = details | |||||
| } | |||||
| var localizedDescription: String { | |||||
| return | |||||
| "PigeonError(code: \(code), message: \(message ?? "<nil>"), details: \(details ?? "<nil>")" | |||||
| } | |||||
| } | |||||
| private func wrapResult(_ result: Any?) -> [Any?] { | |||||
| return [result] | |||||
| } | |||||
| private func wrapError(_ error: Any) -> [Any?] { | |||||
| if let pigeonError = error as? PigeonError { | |||||
| return [ | |||||
| pigeonError.code, | |||||
| pigeonError.message, | |||||
| pigeonError.details, | |||||
| ] | |||||
| } | |||||
| if let flutterError = error as? FlutterError { | |||||
| return [ | |||||
| flutterError.code, | |||||
| flutterError.message, | |||||
| flutterError.details, | |||||
| ] | |||||
| } | |||||
| return [ | |||||
| "\(error)", | |||||
| "\(type(of: error))", | |||||
| "Stacktrace: \(Thread.callStackSymbols)", | |||||
| ] | |||||
| } | |||||
| private func isNullish(_ value: Any?) -> Bool { | |||||
| return value is NSNull || value == nil | |||||
| } | |||||
| private func nilOrValue<T>(_ value: Any?) -> T? { | |||||
| if value is NSNull { return nil } | |||||
| return value as! T? | |||||
| } | |||||
| /// Possible outcomes of launching a URL. | |||||
| enum LaunchResult: Int { | |||||
| /// The URL was successfully launched (or could be, for `canLaunchUrl`). | |||||
| case success = 0 | |||||
| /// There was no handler available for the URL. | |||||
| case failure = 1 | |||||
| /// The URL could not be launched because it is invalid. | |||||
| case invalidUrl = 2 | |||||
| } | |||||
| /// Possible outcomes of handling a URL within the application. | |||||
| enum InAppLoadResult: Int { | |||||
| /// The URL was successfully loaded. | |||||
| case success = 0 | |||||
| /// The URL did not load successfully. | |||||
| case failedToLoad = 1 | |||||
| /// The URL could not be launched because it is invalid. | |||||
| case invalidUrl = 2 | |||||
| } | |||||
| private class messagesPigeonCodecReader: FlutterStandardReader { | |||||
| override func readValue(ofType type: UInt8) -> Any? { | |||||
| switch type { | |||||
| case 129: | |||||
| let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) | |||||
| if let enumResultAsInt = enumResultAsInt { | |||||
| return LaunchResult(rawValue: enumResultAsInt) | |||||
| } | |||||
| return nil | |||||
| case 130: | |||||
| let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) | |||||
| if let enumResultAsInt = enumResultAsInt { | |||||
| return InAppLoadResult(rawValue: enumResultAsInt) | |||||
| } | |||||
| return nil | |||||
| default: | |||||
| return super.readValue(ofType: type) | |||||
| } | |||||
| } | |||||
| } | |||||
| private class messagesPigeonCodecWriter: FlutterStandardWriter { | |||||
| override func writeValue(_ value: Any) { | |||||
| if let value = value as? LaunchResult { | |||||
| super.writeByte(129) | |||||
| super.writeValue(value.rawValue) | |||||
| } else if let value = value as? InAppLoadResult { | |||||
| super.writeByte(130) | |||||
| super.writeValue(value.rawValue) | |||||
| } else { | |||||
| super.writeValue(value) | |||||
| } | |||||
| } | |||||
| } | |||||
| private class messagesPigeonCodecReaderWriter: FlutterStandardReaderWriter { | |||||
| override func reader(with data: Data) -> FlutterStandardReader { | |||||
| return messagesPigeonCodecReader(data: data) | |||||
| } | |||||
| override func writer(with data: NSMutableData) -> FlutterStandardWriter { | |||||
| return messagesPigeonCodecWriter(data: data) | |||||
| } | |||||
| } | |||||
| class messagesPigeonCodec: FlutterStandardMessageCodec, @unchecked Sendable { | |||||
| static let shared = messagesPigeonCodec(readerWriter: messagesPigeonCodecReaderWriter()) | |||||
| } | |||||
| /// Generated protocol from Pigeon that represents a handler of messages from Flutter. | |||||
| protocol UrlLauncherApi { | |||||
| /// Checks whether a URL can be loaded. | |||||
| func canLaunchUrl(url: String) throws -> LaunchResult | |||||
| /// Opens the URL externally, returning the status of launching it. | |||||
| func launchUrl( | |||||
| url: String, universalLinksOnly: Bool, | |||||
| completion: @escaping (Result<LaunchResult, Error>) -> Void) | |||||
| /// Opens the URL in an in-app SFSafariViewController, returning the results | |||||
| /// of loading it. | |||||
| func openUrlInSafariViewController( | |||||
| url: String, completion: @escaping (Result<InAppLoadResult, Error>) -> Void) | |||||
| /// Closes the view controller opened by [openUrlInSafariViewController]. | |||||
| func closeSafariViewController() throws | |||||
| } | |||||
| /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. | |||||
| class UrlLauncherApiSetup { | |||||
| static var codec: FlutterStandardMessageCodec { messagesPigeonCodec.shared } | |||||
| /// Sets up an instance of `UrlLauncherApi` to handle messages through the `binaryMessenger`. | |||||
| static func setUp( | |||||
| binaryMessenger: FlutterBinaryMessenger, api: UrlLauncherApi?, messageChannelSuffix: String = "" | |||||
| ) { | |||||
| let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" | |||||
| /// Checks whether a URL can be loaded. | |||||
| let canLaunchUrlChannel = FlutterBasicMessageChannel( | |||||
| name: "dev.flutter.pigeon.url_launcher_ios.UrlLauncherApi.canLaunchUrl\(channelSuffix)", | |||||
| binaryMessenger: binaryMessenger, codec: codec) | |||||
| if let api = api { | |||||
| canLaunchUrlChannel.setMessageHandler { message, reply in | |||||
| let args = message as! [Any?] | |||||
| let urlArg = args[0] as! String | |||||
| do { | |||||
| let result = try api.canLaunchUrl(url: urlArg) | |||||
| reply(wrapResult(result)) | |||||
| } catch { | |||||
| reply(wrapError(error)) | |||||
| } | |||||
| } | |||||
| } else { | |||||
| canLaunchUrlChannel.setMessageHandler(nil) | |||||
| } | |||||
| /// Opens the URL externally, returning the status of launching it. | |||||
| let launchUrlChannel = FlutterBasicMessageChannel( | |||||
| name: "dev.flutter.pigeon.url_launcher_ios.UrlLauncherApi.launchUrl\(channelSuffix)", | |||||
| binaryMessenger: binaryMessenger, codec: codec) | |||||
| if let api = api { | |||||
| launchUrlChannel.setMessageHandler { message, reply in | |||||
| let args = message as! [Any?] | |||||
| let urlArg = args[0] as! String | |||||
| let universalLinksOnlyArg = args[1] as! Bool | |||||
| api.launchUrl(url: urlArg, universalLinksOnly: universalLinksOnlyArg) { result in | |||||
| switch result { | |||||
| case .success(let res): | |||||
| reply(wrapResult(res)) | |||||
| case .failure(let error): | |||||
| reply(wrapError(error)) | |||||
| } | |||||
| } | |||||
| } | |||||
| } else { | |||||
| launchUrlChannel.setMessageHandler(nil) | |||||
| } | |||||
| /// Opens the URL in an in-app SFSafariViewController, returning the results | |||||
| /// of loading it. | |||||
| let openUrlInSafariViewControllerChannel = FlutterBasicMessageChannel( | |||||
| name: | |||||
| "dev.flutter.pigeon.url_launcher_ios.UrlLauncherApi.openUrlInSafariViewController\(channelSuffix)", | |||||
| binaryMessenger: binaryMessenger, codec: codec) | |||||
| if let api = api { | |||||
| openUrlInSafariViewControllerChannel.setMessageHandler { message, reply in | |||||
| let args = message as! [Any?] | |||||
| let urlArg = args[0] as! String | |||||
| api.openUrlInSafariViewController(url: urlArg) { result in | |||||
| switch result { | |||||
| case .success(let res): | |||||
| reply(wrapResult(res)) | |||||
| case .failure(let error): | |||||
| reply(wrapError(error)) | |||||
| } | |||||
| } | |||||
| } | |||||
| } else { | |||||
| openUrlInSafariViewControllerChannel.setMessageHandler(nil) | |||||
| } | |||||
| /// Closes the view controller opened by [openUrlInSafariViewController]. | |||||
| let closeSafariViewControllerChannel = FlutterBasicMessageChannel( | |||||
| name: | |||||
| "dev.flutter.pigeon.url_launcher_ios.UrlLauncherApi.closeSafariViewController\(channelSuffix)", | |||||
| binaryMessenger: binaryMessenger, codec: codec) | |||||
| if let api = api { | |||||
| closeSafariViewControllerChannel.setMessageHandler { _, reply in | |||||
| do { | |||||
| try api.closeSafariViewController() | |||||
| reply(wrapResult(nil)) | |||||
| } catch { | |||||
| reply(wrapError(error)) | |||||
| } | |||||
| } | |||||
| } else { | |||||
| closeSafariViewControllerChannel.setMessageHandler(nil) | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,208 @@ | |||||
| // Copyright 2013 The Flutter Authors. All rights reserved. | |||||
| // Use of this source code is governed by a BSD-style license that can be | |||||
| // found in the LICENSE file. | |||||
| // Autogenerated from Pigeon (v22.6.4), do not edit directly. | |||||
| // See also: https://pub.dev/packages/pigeon | |||||
| // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers | |||||
| import 'dart:async'; | |||||
| import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; | |||||
| import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; | |||||
| import 'package:flutter/services.dart'; | |||||
| PlatformException _createConnectionError(String channelName) { | |||||
| return PlatformException( | |||||
| code: 'channel-error', | |||||
| message: 'Unable to establish connection on channel: "$channelName".', | |||||
| ); | |||||
| } | |||||
| /// Possible outcomes of launching a URL. | |||||
| enum LaunchResult { | |||||
| /// The URL was successfully launched (or could be, for `canLaunchUrl`). | |||||
| success, | |||||
| /// There was no handler available for the URL. | |||||
| failure, | |||||
| /// The URL could not be launched because it is invalid. | |||||
| invalidUrl, | |||||
| } | |||||
| /// Possible outcomes of handling a URL within the application. | |||||
| enum InAppLoadResult { | |||||
| /// The URL was successfully loaded. | |||||
| success, | |||||
| /// The URL did not load successfully. | |||||
| failedToLoad, | |||||
| /// The URL could not be launched because it is invalid. | |||||
| invalidUrl, | |||||
| } | |||||
| class _PigeonCodec extends StandardMessageCodec { | |||||
| const _PigeonCodec(); | |||||
| @override | |||||
| void writeValue(WriteBuffer buffer, Object? value) { | |||||
| if (value is int) { | |||||
| buffer.putUint8(4); | |||||
| buffer.putInt64(value); | |||||
| } else if (value is LaunchResult) { | |||||
| buffer.putUint8(129); | |||||
| writeValue(buffer, value.index); | |||||
| } else if (value is InAppLoadResult) { | |||||
| buffer.putUint8(130); | |||||
| writeValue(buffer, value.index); | |||||
| } else { | |||||
| super.writeValue(buffer, value); | |||||
| } | |||||
| } | |||||
| @override | |||||
| Object? readValueOfType(int type, ReadBuffer buffer) { | |||||
| switch (type) { | |||||
| case 129: | |||||
| final int? value = readValue(buffer) as int?; | |||||
| return value == null ? null : LaunchResult.values[value]; | |||||
| case 130: | |||||
| final int? value = readValue(buffer) as int?; | |||||
| return value == null ? null : InAppLoadResult.values[value]; | |||||
| default: | |||||
| return super.readValueOfType(type, buffer); | |||||
| } | |||||
| } | |||||
| } | |||||
| class UrlLauncherApi { | |||||
| /// Constructor for [UrlLauncherApi]. The [binaryMessenger] named argument is | |||||
| /// available for dependency injection. If it is left null, the default | |||||
| /// BinaryMessenger will be used which routes to the host platform. | |||||
| UrlLauncherApi( | |||||
| {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) | |||||
| : pigeonVar_binaryMessenger = binaryMessenger, | |||||
| pigeonVar_messageChannelSuffix = | |||||
| messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; | |||||
| final BinaryMessenger? pigeonVar_binaryMessenger; | |||||
| static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec(); | |||||
| final String pigeonVar_messageChannelSuffix; | |||||
| /// Checks whether a URL can be loaded. | |||||
| Future<LaunchResult> canLaunchUrl(String url) async { | |||||
| final String pigeonVar_channelName = | |||||
| 'dev.flutter.pigeon.url_launcher_ios.UrlLauncherApi.canLaunchUrl$pigeonVar_messageChannelSuffix'; | |||||
| final BasicMessageChannel<Object?> pigeonVar_channel = | |||||
| BasicMessageChannel<Object?>( | |||||
| pigeonVar_channelName, | |||||
| pigeonChannelCodec, | |||||
| binaryMessenger: pigeonVar_binaryMessenger, | |||||
| ); | |||||
| final List<Object?>? pigeonVar_replyList = | |||||
| await pigeonVar_channel.send(<Object?>[url]) as List<Object?>?; | |||||
| if (pigeonVar_replyList == null) { | |||||
| throw _createConnectionError(pigeonVar_channelName); | |||||
| } else if (pigeonVar_replyList.length > 1) { | |||||
| throw PlatformException( | |||||
| code: pigeonVar_replyList[0]! as String, | |||||
| message: pigeonVar_replyList[1] as String?, | |||||
| details: pigeonVar_replyList[2], | |||||
| ); | |||||
| } else if (pigeonVar_replyList[0] == null) { | |||||
| throw PlatformException( | |||||
| code: 'null-error', | |||||
| message: 'Host platform returned null value for non-null return value.', | |||||
| ); | |||||
| } else { | |||||
| return (pigeonVar_replyList[0] as LaunchResult?)!; | |||||
| } | |||||
| } | |||||
| /// Opens the URL externally, returning the status of launching it. | |||||
| Future<LaunchResult> launchUrl(String url, bool universalLinksOnly) async { | |||||
| final String pigeonVar_channelName = | |||||
| 'dev.flutter.pigeon.url_launcher_ios.UrlLauncherApi.launchUrl$pigeonVar_messageChannelSuffix'; | |||||
| final BasicMessageChannel<Object?> pigeonVar_channel = | |||||
| BasicMessageChannel<Object?>( | |||||
| pigeonVar_channelName, | |||||
| pigeonChannelCodec, | |||||
| binaryMessenger: pigeonVar_binaryMessenger, | |||||
| ); | |||||
| final List<Object?>? pigeonVar_replyList = await pigeonVar_channel | |||||
| .send(<Object?>[url, universalLinksOnly]) as List<Object?>?; | |||||
| if (pigeonVar_replyList == null) { | |||||
| throw _createConnectionError(pigeonVar_channelName); | |||||
| } else if (pigeonVar_replyList.length > 1) { | |||||
| throw PlatformException( | |||||
| code: pigeonVar_replyList[0]! as String, | |||||
| message: pigeonVar_replyList[1] as String?, | |||||
| details: pigeonVar_replyList[2], | |||||
| ); | |||||
| } else if (pigeonVar_replyList[0] == null) { | |||||
| throw PlatformException( | |||||
| code: 'null-error', | |||||
| message: 'Host platform returned null value for non-null return value.', | |||||
| ); | |||||
| } else { | |||||
| return (pigeonVar_replyList[0] as LaunchResult?)!; | |||||
| } | |||||
| } | |||||
| /// Opens the URL in an in-app SFSafariViewController, returning the results | |||||
| /// of loading it. | |||||
| Future<InAppLoadResult> openUrlInSafariViewController(String url) async { | |||||
| final String pigeonVar_channelName = | |||||
| 'dev.flutter.pigeon.url_launcher_ios.UrlLauncherApi.openUrlInSafariViewController$pigeonVar_messageChannelSuffix'; | |||||
| final BasicMessageChannel<Object?> pigeonVar_channel = | |||||
| BasicMessageChannel<Object?>( | |||||
| pigeonVar_channelName, | |||||
| pigeonChannelCodec, | |||||
| binaryMessenger: pigeonVar_binaryMessenger, | |||||
| ); | |||||
| final List<Object?>? pigeonVar_replyList = | |||||
| await pigeonVar_channel.send(<Object?>[url]) as List<Object?>?; | |||||
| if (pigeonVar_replyList == null) { | |||||
| throw _createConnectionError(pigeonVar_channelName); | |||||
| } else if (pigeonVar_replyList.length > 1) { | |||||
| throw PlatformException( | |||||
| code: pigeonVar_replyList[0]! as String, | |||||
| message: pigeonVar_replyList[1] as String?, | |||||
| details: pigeonVar_replyList[2], | |||||
| ); | |||||
| } else if (pigeonVar_replyList[0] == null) { | |||||
| throw PlatformException( | |||||
| code: 'null-error', | |||||
| message: 'Host platform returned null value for non-null return value.', | |||||
| ); | |||||
| } else { | |||||
| return (pigeonVar_replyList[0] as InAppLoadResult?)!; | |||||
| } | |||||
| } | |||||
| /// Closes the view controller opened by [openUrlInSafariViewController]. | |||||
| Future<void> closeSafariViewController() async { | |||||
| final String pigeonVar_channelName = | |||||
| 'dev.flutter.pigeon.url_launcher_ios.UrlLauncherApi.closeSafariViewController$pigeonVar_messageChannelSuffix'; | |||||
| final BasicMessageChannel<Object?> pigeonVar_channel = | |||||
| BasicMessageChannel<Object?>( | |||||
| pigeonVar_channelName, | |||||
| pigeonChannelCodec, | |||||
| binaryMessenger: pigeonVar_binaryMessenger, | |||||
| ); | |||||
| final List<Object?>? pigeonVar_replyList = | |||||
| await pigeonVar_channel.send(null) as List<Object?>?; | |||||
| if (pigeonVar_replyList == null) { | |||||
| throw _createConnectionError(pigeonVar_channelName); | |||||
| } else if (pigeonVar_replyList.length > 1) { | |||||
| throw PlatformException( | |||||
| code: pigeonVar_replyList[0]! as String, | |||||
| message: pigeonVar_replyList[1] as String?, | |||||
| details: pigeonVar_replyList[2], | |||||
| ); | |||||
| } else { | |||||
| return; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,172 @@ | |||||
| // Copyright 2013 The Flutter 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 'package:flutter/foundation.dart' show visibleForTesting; | |||||
| import 'package:flutter/services.dart'; | |||||
| import 'package:url_launcher_platform_interface/link.dart'; | |||||
| import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; | |||||
| import 'src/messages.g.dart'; | |||||
| /// An implementation of [UrlLauncherPlatform] for iOS. | |||||
| class UrlLauncherIOS extends UrlLauncherPlatform { | |||||
| /// Creates a new plugin implementation instance. | |||||
| UrlLauncherIOS({ | |||||
| @visibleForTesting UrlLauncherApi? api, | |||||
| }) : _hostApi = api ?? UrlLauncherApi(); | |||||
| final UrlLauncherApi _hostApi; | |||||
| /// Registers this class as the default instance of [UrlLauncherPlatform]. | |||||
| static void registerWith() { | |||||
| UrlLauncherPlatform.instance = UrlLauncherIOS(); | |||||
| } | |||||
| @override | |||||
| final LinkDelegate? linkDelegate = null; | |||||
| @override | |||||
| Future<bool> canLaunch(String url) async { | |||||
| final LaunchResult result = await _hostApi.canLaunchUrl(url); | |||||
| return _mapLaunchResult(result); | |||||
| } | |||||
| @override | |||||
| Future<void> closeWebView() { | |||||
| return _hostApi.closeSafariViewController(); | |||||
| } | |||||
| @override | |||||
| Future<bool> launch( | |||||
| String url, { | |||||
| required bool useSafariVC, | |||||
| required bool useWebView, | |||||
| required bool enableJavaScript, | |||||
| required bool enableDomStorage, | |||||
| required bool universalLinksOnly, | |||||
| required Map<String, String> headers, | |||||
| String? webOnlyWindowName, | |||||
| }) async { | |||||
| final PreferredLaunchMode mode; | |||||
| if (useSafariVC) { | |||||
| mode = PreferredLaunchMode.inAppBrowserView; | |||||
| } else if (universalLinksOnly) { | |||||
| mode = PreferredLaunchMode.externalNonBrowserApplication; | |||||
| } else { | |||||
| mode = PreferredLaunchMode.externalApplication; | |||||
| } | |||||
| return launchUrl( | |||||
| url, | |||||
| LaunchOptions( | |||||
| mode: mode, | |||||
| webViewConfiguration: InAppWebViewConfiguration( | |||||
| enableDomStorage: enableDomStorage, | |||||
| enableJavaScript: enableJavaScript, | |||||
| headers: headers))); | |||||
| } | |||||
| @override | |||||
| Future<bool> launchUrl(String url, LaunchOptions options) async { | |||||
| final bool inApp; | |||||
| switch (options.mode) { | |||||
| case PreferredLaunchMode.inAppWebView: | |||||
| case PreferredLaunchMode.inAppBrowserView: | |||||
| // The iOS implementation doesn't distinguish between these two modes; | |||||
| // both are treated as inAppBrowserView. | |||||
| inApp = true; | |||||
| case PreferredLaunchMode.externalApplication: | |||||
| case PreferredLaunchMode.externalNonBrowserApplication: | |||||
| inApp = false; | |||||
| case PreferredLaunchMode.platformDefault: | |||||
| // Intentionally treat any new values as platformDefault; support for any | |||||
| // new mode requires intentional opt-in, otherwise falling back is the | |||||
| // documented behavior. | |||||
| // ignore: no_default_cases, unreachable_switch_default | |||||
| default: | |||||
| // By default, open web URLs in the application. | |||||
| inApp = url.startsWith('http:') || url.startsWith('https:'); | |||||
| } | |||||
| if (inApp) { | |||||
| return _mapInAppLoadResult( | |||||
| await _hostApi.openUrlInSafariViewController(url), | |||||
| url: url); | |||||
| } else { | |||||
| return _mapLaunchResult(await _hostApi.launchUrl(url, | |||||
| options.mode == PreferredLaunchMode.externalNonBrowserApplication)); | |||||
| } | |||||
| } | |||||
| @override | |||||
| Future<bool> supportsMode(PreferredLaunchMode mode) async { | |||||
| switch (mode) { | |||||
| case PreferredLaunchMode.platformDefault: | |||||
| case PreferredLaunchMode.inAppWebView: | |||||
| case PreferredLaunchMode.inAppBrowserView: | |||||
| case PreferredLaunchMode.externalApplication: | |||||
| case PreferredLaunchMode.externalNonBrowserApplication: | |||||
| return true; | |||||
| // Default is a desired behavior here since support for new modes is | |||||
| // always opt-in, and the enum lives in a different package, so silently | |||||
| // adding "false" for new values is the correct behavior. | |||||
| // ignore: no_default_cases, unreachable_switch_default | |||||
| default: | |||||
| return false; | |||||
| } | |||||
| } | |||||
| @override | |||||
| Future<bool> supportsCloseForMode(PreferredLaunchMode mode) async { | |||||
| return mode == PreferredLaunchMode.inAppWebView || | |||||
| mode == PreferredLaunchMode.inAppBrowserView; | |||||
| } | |||||
| bool _mapLaunchResult(LaunchResult result) { | |||||
| switch (result) { | |||||
| case LaunchResult.success: | |||||
| return true; | |||||
| case LaunchResult.failure: | |||||
| return false; | |||||
| case LaunchResult.invalidUrl: | |||||
| throw _invalidUrlException(); | |||||
| } | |||||
| } | |||||
| bool _mapInAppLoadResult(InAppLoadResult result, {required String url}) { | |||||
| switch (result) { | |||||
| case InAppLoadResult.success: | |||||
| return true; | |||||
| case InAppLoadResult.failedToLoad: | |||||
| throw _failedSafariViewControllerLoadException(url); | |||||
| case InAppLoadResult.invalidUrl: | |||||
| throw _invalidUrlException(); | |||||
| } | |||||
| } | |||||
| // TODO(stuartmorgan): Remove this as part of standardizing error handling. | |||||
| // See https://github.com/flutter/flutter/issues/127665 | |||||
| // | |||||
| // This PlatformException (including the exact string details, since those | |||||
| // are a defacto part of the API) is for compatibility with the previous | |||||
| // native implementation. | |||||
| PlatformException _invalidUrlException() { | |||||
| throw PlatformException( | |||||
| code: 'argument_error', | |||||
| message: 'Unable to parse URL', | |||||
| ); | |||||
| } | |||||
| // TODO(stuartmorgan): Remove this as part of standardizing error handling. | |||||
| // See https://github.com/flutter/flutter/issues/127665 | |||||
| // | |||||
| // This PlatformException (including the exact string details, since those | |||||
| // are a defacto part of the API) is for compatibility with the previous | |||||
| // native implementation. | |||||
| PlatformException _failedSafariViewControllerLoadException(String url) { | |||||
| throw PlatformException( | |||||
| code: 'Error', | |||||
| message: 'Error while launching $url', | |||||
| ); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,3 @@ | |||||
| Copyright 2013 The Flutter Authors. All rights reserved. | |||||
| Use of this source code is governed by a BSD-style license that can be | |||||
| found in the LICENSE file. | |||||
| @@ -0,0 +1,56 @@ | |||||
| // Copyright 2013 The Flutter 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 'package:pigeon/pigeon.dart'; | |||||
| @ConfigurePigeon(PigeonOptions( | |||||
| dartOut: 'lib/src/messages.g.dart', | |||||
| swiftOut: 'ios/url_launcher_ios/Sources/url_launcher_ios/messages.g.swift', | |||||
| copyrightHeader: 'pigeons/copyright.txt', | |||||
| )) | |||||
| /// Possible outcomes of launching a URL. | |||||
| enum LaunchResult { | |||||
| /// The URL was successfully launched (or could be, for `canLaunchUrl`). | |||||
| success, | |||||
| /// There was no handler available for the URL. | |||||
| failure, | |||||
| /// The URL could not be launched because it is invalid. | |||||
| invalidUrl, | |||||
| } | |||||
| /// Possible outcomes of handling a URL within the application. | |||||
| enum InAppLoadResult { | |||||
| /// The URL was successfully loaded. | |||||
| success, | |||||
| /// The URL did not load successfully. | |||||
| failedToLoad, | |||||
| /// The URL could not be launched because it is invalid. | |||||
| invalidUrl, | |||||
| } | |||||
| @HostApi() | |||||
| abstract class UrlLauncherApi { | |||||
| /// Checks whether a URL can be loaded. | |||||
| @ObjCSelector('canLaunchURL:') | |||||
| LaunchResult canLaunchUrl(String url); | |||||
| /// Opens the URL externally, returning the status of launching it. | |||||
| @async | |||||
| @ObjCSelector('launchURL:universalLinksOnly:') | |||||
| LaunchResult launchUrl(String url, bool universalLinksOnly); | |||||
| /// Opens the URL in an in-app SFSafariViewController, returning the results | |||||
| /// of loading it. | |||||
| @async | |||||
| @ObjCSelector('openSafariViewControllerWithURL:') | |||||
| InAppLoadResult openUrlInSafariViewController(String url); | |||||
| /// Closes the view controller opened by [openUrlInSafariViewController]. | |||||
| void closeSafariViewController(); | |||||
| } | |||||
| @@ -0,0 +1,37 @@ | |||||
| name: url_launcher_ios | |||||
| description: iOS implementation of the url_launcher plugin. | |||||
| repository: https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_ios | |||||
| issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+url_launcher%22 | |||||
| version: 6.3.2 | |||||
| environment: | |||||
| sdk: ^3.1.0 | |||||
| flutter: ">=3.19.0" | |||||
| flutter: | |||||
| plugin: | |||||
| implements: url_launcher | |||||
| platforms: | |||||
| ios: | |||||
| pluginClass: URLLauncherPlugin | |||||
| dartPluginClass: UrlLauncherIOS | |||||
| dependencies: | |||||
| flutter: | |||||
| sdk: flutter | |||||
| url_launcher_platform_interface: ^2.2.0 | |||||
| dev_dependencies: | |||||
| build_runner: ^2.3.3 | |||||
| flutter_test: | |||||
| sdk: flutter | |||||
| mockito: ^5.4.4 | |||||
| pigeon: ^22.6.4 | |||||
| plugin_platform_interface: ^2.1.7 | |||||
| test: ^1.16.3 | |||||
| topics: | |||||
| - links | |||||
| - os-integration | |||||
| - url-launcher | |||||
| - urls | |||||
| @@ -0,0 +1,370 @@ | |||||
| // Copyright 2013 The Flutter 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 'package:flutter/services.dart'; | |||||
| import 'package:flutter_test/flutter_test.dart'; | |||||
| import 'package:mockito/annotations.dart'; | |||||
| import 'package:mockito/mockito.dart'; | |||||
| import 'package:url_launcher_ios/src/messages.g.dart'; | |||||
| import 'package:url_launcher_ios/url_launcher_ios.dart'; | |||||
| import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; | |||||
| import 'url_launcher_ios_test.mocks.dart'; | |||||
| // A web URL to use in tests where the specifics of the URL don't matter. | |||||
| const String _webUrl = 'https://example.com/'; | |||||
| @GenerateMocks(<Type>[UrlLauncherApi]) | |||||
| void main() { | |||||
| late MockUrlLauncherApi api; | |||||
| setUp(() { | |||||
| api = MockUrlLauncherApi(); | |||||
| }); | |||||
| test('registers instance', () { | |||||
| UrlLauncherIOS.registerWith(); | |||||
| expect(UrlLauncherPlatform.instance, isA<UrlLauncherIOS>()); | |||||
| }); | |||||
| group('canLaunch', () { | |||||
| test('handles success', () async { | |||||
| when(api.canLaunchUrl(_webUrl)) | |||||
| .thenAnswer((_) async => LaunchResult.success); | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| expect(await launcher.canLaunch(_webUrl), true); | |||||
| }); | |||||
| test('handles failure', () async { | |||||
| when(api.canLaunchUrl(_webUrl)) | |||||
| .thenAnswer((_) async => LaunchResult.failure); | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| expect(await launcher.canLaunch(_webUrl), false); | |||||
| }); | |||||
| test('throws PlatformException for invalid URL', () async { | |||||
| when(api.canLaunchUrl(_webUrl)) | |||||
| .thenAnswer((_) async => LaunchResult.invalidUrl); | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| await expectLater( | |||||
| launcher.canLaunch(_webUrl), | |||||
| throwsA(isA<PlatformException>().having( | |||||
| (PlatformException e) => e.code, 'code', 'argument_error'))); | |||||
| }); | |||||
| }); | |||||
| group('legacy launch', () { | |||||
| test('handles success', () async { | |||||
| when(api.launchUrl(_webUrl, any)) | |||||
| .thenAnswer((_) async => LaunchResult.success); | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| expect( | |||||
| await launcher.launch( | |||||
| _webUrl, | |||||
| useSafariVC: false, | |||||
| useWebView: false, | |||||
| enableJavaScript: false, | |||||
| enableDomStorage: false, | |||||
| universalLinksOnly: false, | |||||
| headers: const <String, String>{}, | |||||
| ), | |||||
| true); | |||||
| verifyNever(api.openUrlInSafariViewController(any)); | |||||
| }); | |||||
| test('handles failure', () async { | |||||
| when(api.launchUrl(_webUrl, any)) | |||||
| .thenAnswer((_) async => LaunchResult.failure); | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| expect( | |||||
| await launcher.launch( | |||||
| _webUrl, | |||||
| useSafariVC: false, | |||||
| useWebView: false, | |||||
| enableJavaScript: false, | |||||
| enableDomStorage: false, | |||||
| universalLinksOnly: false, | |||||
| headers: const <String, String>{}, | |||||
| ), | |||||
| false); | |||||
| verifyNever(api.openUrlInSafariViewController(any)); | |||||
| }); | |||||
| test('throws PlatformException for invalid URL', () async { | |||||
| when(api.launchUrl(_webUrl, any)) | |||||
| .thenAnswer((_) async => LaunchResult.invalidUrl); | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| await expectLater( | |||||
| launcher.launch( | |||||
| _webUrl, | |||||
| useSafariVC: false, | |||||
| useWebView: false, | |||||
| enableJavaScript: false, | |||||
| enableDomStorage: false, | |||||
| universalLinksOnly: false, | |||||
| headers: const <String, String>{}, | |||||
| ), | |||||
| throwsA(isA<PlatformException>().having( | |||||
| (PlatformException e) => e.code, 'code', 'argument_error'))); | |||||
| }); | |||||
| test('force SafariVC is handled', () async { | |||||
| when(api.openUrlInSafariViewController(_webUrl)) | |||||
| .thenAnswer((_) async => InAppLoadResult.success); | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| expect( | |||||
| await launcher.launch( | |||||
| _webUrl, | |||||
| useSafariVC: true, | |||||
| useWebView: false, | |||||
| enableJavaScript: false, | |||||
| enableDomStorage: false, | |||||
| universalLinksOnly: false, | |||||
| headers: const <String, String>{}, | |||||
| ), | |||||
| true); | |||||
| verifyNever(api.launchUrl(any, any)); | |||||
| }); | |||||
| test('universal links only is handled', () async { | |||||
| when(api.launchUrl(_webUrl, any)) | |||||
| .thenAnswer((_) async => LaunchResult.success); | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| expect( | |||||
| await launcher.launch( | |||||
| _webUrl, | |||||
| useSafariVC: false, | |||||
| useWebView: false, | |||||
| enableJavaScript: false, | |||||
| enableDomStorage: false, | |||||
| universalLinksOnly: true, | |||||
| headers: const <String, String>{}, | |||||
| ), | |||||
| true); | |||||
| verifyNever(api.openUrlInSafariViewController(any)); | |||||
| }); | |||||
| test('disallowing SafariVC is handled', () async { | |||||
| when(api.launchUrl(_webUrl, any)) | |||||
| .thenAnswer((_) async => LaunchResult.success); | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| expect( | |||||
| await launcher.launch( | |||||
| _webUrl, | |||||
| useSafariVC: false, | |||||
| useWebView: false, | |||||
| enableJavaScript: false, | |||||
| enableDomStorage: false, | |||||
| universalLinksOnly: false, | |||||
| headers: const <String, String>{}, | |||||
| ), | |||||
| true); | |||||
| verifyNever(api.openUrlInSafariViewController(any)); | |||||
| }); | |||||
| }); | |||||
| test('closeWebView calls through', () async { | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| await launcher.closeWebView(); | |||||
| verify(api.closeSafariViewController()).called(1); | |||||
| }); | |||||
| group('launch without webview', () { | |||||
| test('calls through', () async { | |||||
| when(api.launchUrl(_webUrl, any)) | |||||
| .thenAnswer((_) async => LaunchResult.success); | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| final bool launched = await launcher.launchUrl( | |||||
| _webUrl, | |||||
| const LaunchOptions(mode: PreferredLaunchMode.externalApplication), | |||||
| ); | |||||
| expect(launched, true); | |||||
| verifyNever(api.openUrlInSafariViewController(any)); | |||||
| }); | |||||
| test('throws PlatformException for invalid URL', () async { | |||||
| when(api.launchUrl(_webUrl, any)) | |||||
| .thenAnswer((_) async => LaunchResult.invalidUrl); | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| await expectLater( | |||||
| launcher.launchUrl( | |||||
| _webUrl, | |||||
| const LaunchOptions(mode: PreferredLaunchMode.externalApplication), | |||||
| ), | |||||
| throwsA(isA<PlatformException>().having( | |||||
| (PlatformException e) => e.code, 'code', 'argument_error'))); | |||||
| }); | |||||
| }); | |||||
| group('launch with Safari view controller', () { | |||||
| test('calls through with inAppWebView', () async { | |||||
| when(api.openUrlInSafariViewController(_webUrl)) | |||||
| .thenAnswer((_) async => InAppLoadResult.success); | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| final bool launched = await launcher.launchUrl( | |||||
| _webUrl, const LaunchOptions(mode: PreferredLaunchMode.inAppWebView)); | |||||
| expect(launched, true); | |||||
| verifyNever(api.launchUrl(any, any)); | |||||
| }); | |||||
| test('calls through with inAppBrowserView', () async { | |||||
| when(api.openUrlInSafariViewController(_webUrl)) | |||||
| .thenAnswer((_) async => InAppLoadResult.success); | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| final bool launched = await launcher.launchUrl(_webUrl, | |||||
| const LaunchOptions(mode: PreferredLaunchMode.inAppBrowserView)); | |||||
| expect(launched, true); | |||||
| verifyNever(api.launchUrl(any, any)); | |||||
| }); | |||||
| test('throws PlatformException for invalid URL', () async { | |||||
| when(api.openUrlInSafariViewController(_webUrl)) | |||||
| .thenAnswer((_) async => InAppLoadResult.invalidUrl); | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| await expectLater( | |||||
| launcher.launchUrl(_webUrl, | |||||
| const LaunchOptions(mode: PreferredLaunchMode.inAppWebView)), | |||||
| throwsA(isA<PlatformException>().having( | |||||
| (PlatformException e) => e.code, 'code', 'argument_error'))); | |||||
| }); | |||||
| test('throws PlatformException for load failure', () async { | |||||
| when(api.openUrlInSafariViewController(_webUrl)) | |||||
| .thenAnswer((_) async => InAppLoadResult.failedToLoad); | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| await expectLater( | |||||
| launcher.launchUrl(_webUrl, | |||||
| const LaunchOptions(mode: PreferredLaunchMode.inAppWebView)), | |||||
| throwsA(isA<PlatformException>() | |||||
| .having((PlatformException e) => e.code, 'code', 'Error'))); | |||||
| }); | |||||
| }); | |||||
| group('launch with universal links', () { | |||||
| test('calls through', () async { | |||||
| when(api.launchUrl(_webUrl, any)) | |||||
| .thenAnswer((_) async => LaunchResult.success); | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| final bool launched = await launcher.launchUrl( | |||||
| _webUrl, | |||||
| const LaunchOptions( | |||||
| mode: PreferredLaunchMode.externalNonBrowserApplication), | |||||
| ); | |||||
| expect(launched, true); | |||||
| verifyNever(api.openUrlInSafariViewController(any)); | |||||
| }); | |||||
| test('throws PlatformException for invalid URL', () async { | |||||
| when(api.launchUrl(_webUrl, any)) | |||||
| .thenAnswer((_) async => LaunchResult.invalidUrl); | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| await expectLater( | |||||
| launcher.launchUrl( | |||||
| _webUrl, | |||||
| const LaunchOptions( | |||||
| mode: PreferredLaunchMode.externalNonBrowserApplication)), | |||||
| throwsA(isA<PlatformException>().having( | |||||
| (PlatformException e) => e.code, 'code', 'argument_error'))); | |||||
| }); | |||||
| }); | |||||
| group('launch with platform default', () { | |||||
| test('uses Safari view controller for http', () async { | |||||
| const String httpUrl = 'http://example.com/'; | |||||
| when(api.openUrlInSafariViewController(httpUrl)) | |||||
| .thenAnswer((_) async => InAppLoadResult.success); | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| final bool launched = | |||||
| await launcher.launchUrl(httpUrl, const LaunchOptions()); | |||||
| expect(launched, true); | |||||
| verifyNever(api.launchUrl(any, any)); | |||||
| }); | |||||
| test('uses Safari view controller for https', () async { | |||||
| const String httpsUrl = 'https://example.com/'; | |||||
| when(api.openUrlInSafariViewController(httpsUrl)) | |||||
| .thenAnswer((_) async => InAppLoadResult.success); | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| final bool launched = | |||||
| await launcher.launchUrl(httpsUrl, const LaunchOptions()); | |||||
| expect(launched, true); | |||||
| verifyNever(api.launchUrl(any, any)); | |||||
| }); | |||||
| test('uses standard external for other schemes', () async { | |||||
| const String nonWebUrl = 'supportedcustomscheme://example.com/'; | |||||
| when(api.launchUrl(nonWebUrl, any)) | |||||
| .thenAnswer((_) async => LaunchResult.success); | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| final bool launched = | |||||
| await launcher.launchUrl(nonWebUrl, const LaunchOptions()); | |||||
| expect(launched, true); | |||||
| verifyNever(api.openUrlInSafariViewController(any)); | |||||
| }); | |||||
| }); | |||||
| group('supportsMode', () { | |||||
| test('returns true for platformDefault', () async { | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| expect(await launcher.supportsMode(PreferredLaunchMode.platformDefault), | |||||
| true); | |||||
| }); | |||||
| test('returns true for external application', () async { | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| expect( | |||||
| await launcher.supportsMode(PreferredLaunchMode.externalApplication), | |||||
| true); | |||||
| }); | |||||
| test('returns true for external non-browser application', () async { | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| expect( | |||||
| await launcher | |||||
| .supportsMode(PreferredLaunchMode.externalNonBrowserApplication), | |||||
| true); | |||||
| }); | |||||
| test('returns true for in app web view', () async { | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| expect( | |||||
| await launcher.supportsMode(PreferredLaunchMode.inAppWebView), true); | |||||
| }); | |||||
| test('returns true for in app browser view', () async { | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| expect(await launcher.supportsMode(PreferredLaunchMode.inAppBrowserView), | |||||
| true); | |||||
| }); | |||||
| }); | |||||
| group('supportsCloseForMode', () { | |||||
| test('returns true for in app web view', () async { | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| expect( | |||||
| await launcher.supportsCloseForMode(PreferredLaunchMode.inAppWebView), | |||||
| true); | |||||
| }); | |||||
| test('returns true for in app browser view', () async { | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| expect( | |||||
| await launcher | |||||
| .supportsCloseForMode(PreferredLaunchMode.inAppBrowserView), | |||||
| true); | |||||
| }); | |||||
| test('returns false for other modes', () async { | |||||
| final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); | |||||
| expect( | |||||
| await launcher | |||||
| .supportsCloseForMode(PreferredLaunchMode.externalApplication), | |||||
| false); | |||||
| expect( | |||||
| await launcher.supportsCloseForMode( | |||||
| PreferredLaunchMode.externalNonBrowserApplication), | |||||
| false); | |||||
| }); | |||||
| }); | |||||
| } | |||||
| @@ -0,0 +1,89 @@ | |||||
| // Mocks generated by Mockito 5.4.4 from annotations | |||||
| // in url_launcher_ios/test/url_launcher_ios_test.dart. | |||||
| // Do not manually edit this file. | |||||
| // ignore_for_file: no_leading_underscores_for_library_prefixes | |||||
| import 'dart:async' as _i4; | |||||
| import 'package:mockito/mockito.dart' as _i1; | |||||
| import 'package:mockito/src/dummies.dart' as _i3; | |||||
| import 'package:url_launcher_ios/src/messages.g.dart' as _i2; | |||||
| // ignore_for_file: type=lint | |||||
| // ignore_for_file: avoid_redundant_argument_values | |||||
| // ignore_for_file: avoid_setters_without_getters | |||||
| // ignore_for_file: comment_references | |||||
| // ignore_for_file: deprecated_member_use | |||||
| // ignore_for_file: deprecated_member_use_from_same_package | |||||
| // ignore_for_file: implementation_imports | |||||
| // ignore_for_file: invalid_use_of_visible_for_testing_member | |||||
| // ignore_for_file: prefer_const_constructors | |||||
| // ignore_for_file: unnecessary_parenthesis | |||||
| // ignore_for_file: camel_case_types | |||||
| // ignore_for_file: subtype_of_sealed_class | |||||
| /// A class which mocks [UrlLauncherApi]. | |||||
| /// | |||||
| /// See the documentation for Mockito's code generation for more information. | |||||
| class MockUrlLauncherApi extends _i1.Mock implements _i2.UrlLauncherApi { | |||||
| MockUrlLauncherApi() { | |||||
| _i1.throwOnMissingStub(this); | |||||
| } | |||||
| @override | |||||
| String get pigeonVar_messageChannelSuffix => (super.noSuchMethod( | |||||
| Invocation.getter(#pigeonVar_messageChannelSuffix), | |||||
| returnValue: _i3.dummyValue<String>( | |||||
| this, | |||||
| Invocation.getter(#pigeonVar_messageChannelSuffix), | |||||
| ), | |||||
| ) as String); | |||||
| @override | |||||
| _i4.Future<_i2.LaunchResult> canLaunchUrl(String? url) => (super.noSuchMethod( | |||||
| Invocation.method( | |||||
| #canLaunchUrl, | |||||
| [url], | |||||
| ), | |||||
| returnValue: | |||||
| _i4.Future<_i2.LaunchResult>.value(_i2.LaunchResult.success), | |||||
| ) as _i4.Future<_i2.LaunchResult>); | |||||
| @override | |||||
| _i4.Future<_i2.LaunchResult> launchUrl( | |||||
| String? url, | |||||
| bool? universalLinksOnly, | |||||
| ) => | |||||
| (super.noSuchMethod( | |||||
| Invocation.method( | |||||
| #launchUrl, | |||||
| [ | |||||
| url, | |||||
| universalLinksOnly, | |||||
| ], | |||||
| ), | |||||
| returnValue: | |||||
| _i4.Future<_i2.LaunchResult>.value(_i2.LaunchResult.success), | |||||
| ) as _i4.Future<_i2.LaunchResult>); | |||||
| @override | |||||
| _i4.Future<_i2.InAppLoadResult> openUrlInSafariViewController(String? url) => | |||||
| (super.noSuchMethod( | |||||
| Invocation.method( | |||||
| #openUrlInSafariViewController, | |||||
| [url], | |||||
| ), | |||||
| returnValue: | |||||
| _i4.Future<_i2.InAppLoadResult>.value(_i2.InAppLoadResult.success), | |||||
| ) as _i4.Future<_i2.InAppLoadResult>); | |||||
| @override | |||||
| _i4.Future<void> closeSafariViewController() => (super.noSuchMethod( | |||||
| Invocation.method( | |||||
| #closeSafariViewController, | |||||
| [], | |||||
| ), | |||||
| returnValue: _i4.Future<void>.value(), | |||||
| returnValueForMissingStub: _i4.Future<void>.value(), | |||||
| ) as _i4.Future<void>); | |||||
| } | |||||