Commit 155ffa81 authored by pichillilorenzo's avatar pichillilorenzo

first commit

parents
.DS_Store
.dart_tool/
.packages
.pub/
pubspec.lock
build/
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="h" fileNamingConvention="NONE" />
<pair source="c" header="h" fileNamingConvention="NONE" />
</extensions>
</Objective-C-extensions>
</code_scheme>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Dart SDK">
<CLASSES>
<root url="file:///Users/lorenzo/flutter/bin/cache/dart-sdk/lib/async" />
<root url="file:///Users/lorenzo/flutter/bin/cache/dart-sdk/lib/collection" />
<root url="file:///Users/lorenzo/flutter/bin/cache/dart-sdk/lib/convert" />
<root url="file:///Users/lorenzo/flutter/bin/cache/dart-sdk/lib/core" />
<root url="file:///Users/lorenzo/flutter/bin/cache/dart-sdk/lib/developer" />
<root url="file:///Users/lorenzo/flutter/bin/cache/dart-sdk/lib/html" />
<root url="file:///Users/lorenzo/flutter/bin/cache/dart-sdk/lib/io" />
<root url="file:///Users/lorenzo/flutter/bin/cache/dart-sdk/lib/isolate" />
<root url="file:///Users/lorenzo/flutter/bin/cache/dart-sdk/lib/math" />
<root url="file:///Users/lorenzo/flutter/bin/cache/dart-sdk/lib/mirrors" />
<root url="file:///Users/lorenzo/flutter/bin/cache/dart-sdk/lib/typed_data" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Flutter Plugins" type="FlutterPluginsLibraryType">
<CLASSES>
<root url="file://$PROJECT_DIR$" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="Flutter for Android">
<CLASSES>
<root url="jar:///Users/lorenzo/flutter/bin/cache/artifacts/engine/android-arm/flutter.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="5">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
<item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
</list>
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Android API 24 Platform" project-jdk-type="Android SDK" />
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/flutter_inappbrowser.iml" filepath="$PROJECT_DIR$/flutter_inappbrowser.iml" />
<module fileurl="file://$PROJECT_DIR$/flutter_inappbrowser_android.iml" filepath="$PROJECT_DIR$/flutter_inappbrowser_android.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="example/lib/main.dart" type="FlutterRunConfigurationType" factoryName="Flutter">
<option name="filePath" value="$PROJECT_DIR$/example/lib/main.dart" />
<method />
</configuration>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="9b41f7a2-a71e-4923-91fb-249d7815b3e7" name="Default" comment="" />
<ignored path="$PROJECT_DIR$/.dart_tool/" />
<ignored path="$PROJECT_DIR$/.idea/" />
<ignored path="$PROJECT_DIR$/.pub/" />
<ignored path="$PROJECT_DIR$/build/" />
<ignored path="$PROJECT_DIR$/example/.pub/" />
<ignored path="$PROJECT_DIR$/example/build/" />
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="TRACKING_ENABLED" value="true" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="FileEditorManager">
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
<file leaf-file-name="main.dart" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/example/lib/main.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="38" lean-forward="false" selection-start-line="0" selection-start-column="38" selection-end-line="0" selection-end-column="38" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="flutter_inappbrowser.dart" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/lib/flutter_inappbrowser.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="2760">
<caret line="184" column="71" lean-forward="false" selection-start-line="184" selection-start-column="71" selection-end-line="184" selection-end-column="71" />
<folding>
<element signature="e#0#12626#0" expanded="true" />
<element signature="e#814#834#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file leaf-file-name="pubspec.yaml" pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="15">
<caret line="1" column="133" lean-forward="true" selection-start-line="1" selection-start-column="13" selection-end-line="1" selection-end-column="133" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="README.md" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/README.md">
<provider selected="true" editor-type-id="split-provider[text-editor;markdown-preview-editor]">
<state split_layout="SPLIT">
<first_editor relative-caret-position="60">
<caret line="4" column="66" lean-forward="true" selection-start-line="4" selection-start-column="66" selection-end-line="4" selection-end-column="66" />
<folding>
<marker date="1536884362681" expanded="true" signature="1034:1527" ph="{...}" />
<marker date="1536884362681" expanded="true" signature="1082:1150" ph="{...}" />
<marker date="1536884362681" expanded="true" signature="1196:1263" ph="{...}" />
<marker date="1536884362681" expanded="true" signature="1339:1427" ph="{...}" />
<marker date="1536884362681" expanded="true" signature="1459:1522" ph="{...}" />
<marker date="1536884362681" expanded="true" signature="1519:1522" ph="{...}" />
<marker date="1536884362681" expanded="true" signature="9770:9803" ph="{...}" />
<marker date="1536884362681" expanded="true" signature="9922:9954" ph="{...}" />
<marker date="1536884362681" expanded="true" signature="10114:10146" ph="{...}" />
<marker date="1536884362681" expanded="true" signature="10242:10267" ph="{...}" />
</folding>
</first_editor>
<second_editor />
</state>
</provider>
</entry>
</file>
</leaf>
</component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Class" />
</list>
</option>
</component>
<component name="FindInProjectRecents">
<findStrings>
<find>Resource</find>
<find>(0)</find>
<find>closeDi</find>
<find>hide()</find>
<find>loadUrl</find>
<find>showWebPage</find>
<find>InAppBrowserClient</find>
<find>LOG.</find>
<find>preferences</find>
<find>getPre</find>
<find>client</find>
<find>webView</find>
<find>result.s</find>
<find>result</find>
<find>Client</find>
<find>LOAD_START_EVENT</find>
<find>loadstop</find>
<find>JSONO</find>
<find>closeDialog</find>
<find>LOAD_STOP_EVENT</find>
<find>com.pichillilorenzo.flutterwebview</find>
<find>flutter_webview</find>
<find>show</find>
<find>SELF</find>
<find>customscheme</find>
<find>EXIT</find>
<find>injectScriptCode</find>
<find>injectDeferredObject</find>
<find>sourceFile</find>
</findStrings>
<replaceStrings>
<replace>activity.getPreferences(0)</replace>
<replace>Log.</replace>
<replace>com.pichillilorenzo.flutter_inappbrowser</replace>
<replace>flutter_inappbrowser</replace>
</replaceStrings>
</component>
<component name="GradleLocalSettings">
<option name="externalProjectsViewState">
<projects_view />
</option>
</component>
<component name="IdeDocumentHistory">
<option name="CHANGED_PATHS">
<list>
<option value="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutterwebview/WebViewActivity.java" />
<option value="$PROJECT_DIR$/android/src/main/AndroidManifest.xml" />
<option value="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutterwebview/FlutterWebviewPlugin.java" />
<option value="$PROJECT_DIR$/lib/flutter_webview.dart" />
<option value="$PROJECT_DIR$/example/ios/Podfile" />
<option value="$PROJECT_DIR$/example/ios/Flutter/Debug.xcconfig" />
<option value="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutterwebview/InAppBrowser.java" />
<option value="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutterwebview/InAppBrowserClient.java" />
<option value="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutterwebview/InAppBrowserDialog.java" />
<option value="$PROJECT_DIR$/android/settings.gradle" />
<option value="$PROJECT_DIR$/ios/flutter_inappbrowser.podspec" />
<option value="$PROJECT_DIR$/example/pubspec.yaml" />
<option value="$PROJECT_DIR$/ios/Classes/InAppBrowser.m" />
<option value="$PROJECT_DIR$/ios/Classes/SwiftFlutterPlugin.swift" />
<option value="$PROJECT_DIR$/CHANGELOG.md" />
<option value="$PROJECT_DIR$/LICENSE" />
<option value="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserDialog.java" />
<option value="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserClient.java" />
<option value="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowser.java" />
<option value="$PROJECT_DIR$/lib/flutter_inappbrowser.dart" />
<option value="$PROJECT_DIR$/example/lib/main.dart" />
<option value="$PROJECT_DIR$/README.md" />
<option value="$PROJECT_DIR$/pubspec.yaml" />
</list>
</option>
</component>
<component name="ProjectFrameBounds">
<option name="y" value="23" />
<option name="width" value="1920" />
<option name="height" value="1057" />
</component>
<component name="ProjectView">
<navigator currentView="ProjectPane" proportions="" version="1">
<flattenPackages />
<showMembers />
<showModules />
<showLibraryContents />
<hideEmptyPackages />
<abbreviatePackageNames />
<autoscrollToSource />
<autoscrollFromSource />
<sortByType />
<manualOrder />
<foldersAlwaysOnTop value="true" />
</navigator>
<panes>
<pane id="AndroidView" />
<pane id="ProjectPane">
<subPane>
<expand>
<path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
<item name="android" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
<item name="lib" type="462c0819:PsiDirectoryNode" />
</path>
</expand>
<select />
</subPane>
<option name="show-excluded-files" value="false" />
</pane>
<pane id="PackagesPane" />
<pane id="Scope" />
<pane id="Scratches" />
</panes>
</component>
<component name="PropertiesComponent">
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
<property name="dart.analysis.tool.window.force.activate" value="false" />
<property name="show.migrate.to.gradle.popup" value="false" />
<property name="io.flutter.reload.alreadyRun" value="true" />
</component>
<component name="RecentsManager">
<key name="MoveFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/android/src/main/java" />
</key>
</component>
<component name="RunDashboard">
<option name="ruleStates">
<list>
<RuleState>
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
</RuleState>
<RuleState>
<option name="name" value="StatusDashboardGroupingRule" />
</RuleState>
</list>
</option>
</component>
<component name="RunManager">
<configuration default="true" type="AndroidJUnit" factoryName="Android JUnit">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" />
<option name="MAIN_CLASS_NAME" />
<option name="METHOD_NAME" />
<option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" />
<option name="WORKING_DIRECTORY" value="$MODULE_DIR$" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<envs />
<patterns />
</configuration>
<configuration default="true" type="Application" factoryName="Application">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<option name="MAIN_CLASS_NAME" />
<option name="VM_PARAMETERS" />
<option name="PROGRAM_PARAMETERS" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="ENABLE_SWING_INSPECTOR" value="false" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<module name="" />
<envs />
</configuration>
<configuration default="true" type="JetRunConfigurationType" factoryName="Kotlin">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<option name="VM_PARAMETERS" />
<option name="PROGRAM_PARAMETERS" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="MAIN_CLASS_NAME" />
<option name="WORKING_DIRECTORY" />
<module name="flutter_webview" />
<envs />
</configuration>
<configuration default="true" type="KotlinStandaloneScriptRunConfigurationType" factoryName="Kotlin script">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<option name="filePath" />
<option name="vmParameters" />
<option name="alternativeJrePath" />
<option name="programParameters" />
<option name="passParentEnvs" value="true" />
<option name="workingDirectory" />
<option name="isAlternativeJrePathEnabled" value="false" />
<option name="VM_PARAMETERS" />
<option name="PROGRAM_PARAMETERS" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="MAIN_CLASS_NAME" />
<option name="WORKING_DIRECTORY" />
<module name="flutter_webview" />
<envs />
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<option name="filePath" />
<option name="vmParameters" />
<option name="alternativeJrePath" />
<option name="programParameters" />
<option name="passParentEnvs" value="true" />
<option name="workingDirectory" />
<option name="isAlternativeJrePathEnabled" value="false" />
<option name="VM_PARAMETERS" />
<option name="PROGRAM_PARAMETERS" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="MAIN_CLASS_NAME" />
<option name="WORKING_DIRECTORY" />
<envs />
</configuration>
<configuration default="true" type="Remote" factoryName="Remote">
<option name="USE_SOCKET_TRANSPORT" value="true" />
<option name="SERVER_MODE" value="false" />
<option name="SHMEM_ADDRESS" value="javadebug" />
<option name="HOST" value="localhost" />
<option name="PORT" value="5005" />
</configuration>
<configuration default="true" type="TestNG" factoryName="TestNG">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="SUITE_NAME" />
<option name="PACKAGE_NAME" />
<option name="MAIN_CLASS_NAME" />
<option name="METHOD_NAME" />
<option name="GROUP_NAME" />
<option name="TEST_OBJECT" value="CLASS" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" />
<option name="WORKING_DIRECTORY" value="%MODULE_WORKING_DIR%" />
<option name="OUTPUT_DIRECTORY" />
<option name="ANNOTATION_TYPE" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<option name="USE_DEFAULT_REPORTERS" value="false" />
<option name="PROPERTIES_FILE" />
<envs />
<properties />
<listeners />
</configuration>
<configuration name="&lt;template&gt;" type="Applet" default="true" selected="false">
<option name="MAIN_CLASS_NAME" />
<option name="HTML_FILE_NAME" />
<option name="HTML_USED" value="false" />
<option name="WIDTH" value="400" />
<option name="HEIGHT" value="300" />
<option name="POLICY_FILE" value="$APPLICATION_HOME_DIR$/bin/appletviewer.policy" />
<option name="VM_PARAMETERS" />
</configuration>
<configuration name="&lt;template&gt;" type="JUnit" default="true" selected="false">
<option name="MAIN_CLASS_NAME" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" />
<option name="WORKING_DIRECTORY" value="%MODULE_WORKING_DIR%" />
</configuration>
<configuration name="&lt;template&gt;" type="#org.jetbrains.idea.devkit.run.PluginConfigurationType" default="true" selected="false">
<option name="VM_PARAMETERS" value="-Xmx512m -Xms256m -XX:MaxPermSize=250m -ea" />
</configuration>
</component>
<component name="ShelveChangesManager" show_recycled="false">
<option name="remove_strategy" value="false" />
</component>
<component name="SvnConfiguration">
<configuration />
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="9b41f7a2-a71e-4923-91fb-249d7815b3e7" name="Default" comment="" />
<created>1536836356751</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1536836356751</updated>
</task>
<servers />
</component>
<component name="ToolWindowManager">
<frame x="0" y="23" width="1920" height="1057" extended-state="0" />
<layout>
<window_info id="Android Profiler" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Build Variants" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
<window_info id="Dart Analysis" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3290735" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Flutter Outline" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32977968" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Logcat" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Capture Tool" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Designer" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Device File Explorer" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="true" content_ui="tabs" />
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
<window_info id="Messages" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3290735" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Palette&#9;" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Image Layers" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Capture Analysis" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.26198083" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Terminal" active="true" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.3290735" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Captures" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.18317358" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3290735" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Theme Preview" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
<window_info id="Flutter Inspector" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
</layout>
</component>
<component name="VcsContentAnnotationSettings">
<option name="myLimit" value="2678400000" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
<option name="time" value="2" />
</breakpoint-manager>
<watches-manager />
</component>
<component name="editorHistoryManager">
<entry file="file://$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowser.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="105">
<caret line="74" column="13" lean-forward="false" selection-start-line="74" selection-start-column="13" selection-end-line="74" selection-end-column="13" />
<folding>
<element signature="e#0#34913#0" expanded="false" />
<element signature="e#9355#9356#0" expanded="false" />
<element signature="e#9394#9395#0" expanded="false" />
<element signature="e#9568#9569#0" expanded="false" />
<element signature="e#9607#9608#0" expanded="false" />
<element signature="e#18465#18466#0" expanded="false" />
<element signature="e#18504#18505#0" expanded="false" />
<element signature="e#21476#21477#0" expanded="false" />
<element signature="e#21510#21511#0" expanded="false" />
<element signature="e#22775#22776#0" expanded="false" />
<element signature="e#22812#22813#0" expanded="false" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="270">
<caret line="18" column="34" lean-forward="true" selection-start-line="18" selection-start-column="34" selection-end-line="18" selection-end-column="34" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/lib/main.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="135">
<caret line="9" column="34" lean-forward="true" selection-start-line="9" selection-start-column="34" selection-end-line="9" selection-end-column="34" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutterwebview/WebViewActivity.java" />
<entry file="file://$PROJECT_DIR$/example/android/app/src/main/java/com/pichillilorenzo/flutterwebviewexample/MainActivity.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="135">
<caret line="9" column="19" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="13" selection-end-column="0" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/ios/Classes/SwiftFlutterWebviewPlugin.swift" />
<entry file="file://$PROJECT_DIR$/example/ios/Podfile.lock">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/ios/Flutter/Generated.xcconfig">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/ios/Pods/Manifest.lock">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="330">
<caret line="22" column="0" lean-forward="false" selection-start-line="22" selection-start-column="0" selection-end-line="22" selection-end-column="0" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/ios/Runner/GeneratedPluginRegistrant.m">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/flutter_webview_example.iml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/ios/Flutter/Debug.xcconfig">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="30">
<caret line="2" column="24" lean-forward="false" selection-start-line="2" selection-start-column="24" selection-end-line="2" selection-end-column="24" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/ios/Runner/AppDelegate.swift">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/pubspec.lock">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/ios/Podfile">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="320">
<caret line="56" column="3" lean-forward="false" selection-start-line="56" selection-start-column="3" selection-end-line="56" selection-end-column="3" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/local.properties">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/settings.gradle">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="20" lean-forward="false" selection-start-line="0" selection-start-column="20" selection-end-line="0" selection-end-column="20" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/gradle.properties">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-44">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/src/main/AndroidManifest.xml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="75">
<caret line="5" column="11" lean-forward="false" selection-start-line="5" selection-start-column="11" selection-end-line="5" selection-end-column="11" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/android/settings.gradle">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/android/local.properties">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/android/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/android/gradle.properties">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/android/app/src/main/AndroidManifest.xml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="6" lean-forward="false" selection-start-line="0" selection-start-column="6" selection-end-line="0" selection-end-column="26" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/ios/flutter_inappbrowser.podspec">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="270">
<caret line="18" column="33" lean-forward="false" selection-start-line="18" selection-start-column="33" selection-end-line="18" selection-end-column="33" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/ios/Classes/InAppBrowser.h">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/ios/Classes/InAppBrowser.m">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="270">
<caret line="18" column="50" lean-forward="false" selection-start-line="18" selection-start-column="50" selection-end-line="18" selection-end-column="50" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/flutter_inappbrowser_android.iml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/flutter_inappbrowser.iml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/CHANGELOG.md">
<provider selected="true" editor-type-id="split-provider[text-editor;markdown-preview-editor]">
<state split_layout="SPLIT">
<first_editor relative-caret-position="45">
<caret line="3" column="0" lean-forward="true" selection-start-line="3" selection-start-column="0" selection-end-line="3" selection-end-column="0" />
<folding />
</first_editor>
<second_editor />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/LICENSE">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="15">
<caret line="1" column="31" lean-forward="false" selection-start-line="1" selection-start-column="31" selection-end-line="1" selection-end-column="31" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserDialog.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="285">
<caret line="19" column="3" lean-forward="false" selection-start-line="19" selection-start-column="3" selection-end-line="19" selection-end-column="3" />
<folding>
<element signature="e#0#1715#0" expanded="false" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserClient.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="285">
<caret line="19" column="3" lean-forward="false" selection-start-line="19" selection-start-column="3" selection-end-line="19" selection-end-column="3" />
<folding>
<element signature="e#0#8235#0" expanded="false" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowser.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="285">
<caret line="19" column="3" lean-forward="false" selection-start-line="19" selection-start-column="3" selection-end-line="19" selection-end-column="3" />
<folding>
<element signature="e#0#34913#0" expanded="false" />
<element signature="e#9355#9356#0" expanded="false" />
<element signature="e#9394#9395#0" expanded="false" />
<element signature="e#9568#9569#0" expanded="false" />
<element signature="e#9607#9608#0" expanded="false" />
<element signature="e#18465#18466#0" expanded="false" />
<element signature="e#18504#18505#0" expanded="false" />
<element signature="e#21476#21477#0" expanded="false" />
<element signature="e#21510#21511#0" expanded="false" />
<element signature="e#22775#22776#0" expanded="false" />
<element signature="e#22812#22813#0" expanded="false" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/ios/Classes/SwiftFlutterPlugin.swift">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="1965">
<caret line="131" column="5" lean-forward="true" selection-start-line="131" selection-start-column="5" selection-end-line="131" selection-end-column="5" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/lib/main.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="38" lean-forward="false" selection-start-line="0" selection-start-column="38" selection-end-line="0" selection-end-column="38" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/flutter_inappbrowser.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="2760">
<caret line="184" column="71" lean-forward="false" selection-start-line="184" selection-start-column="71" selection-end-line="184" selection-end-column="71" />
<folding>
<element signature="e#0#12626#0" expanded="true" />
<element signature="e#814#834#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/README.md">
<provider selected="true" editor-type-id="split-provider[text-editor;markdown-preview-editor]">
<state split_layout="SPLIT">
<first_editor relative-caret-position="60">
<caret line="4" column="66" lean-forward="true" selection-start-line="4" selection-start-column="66" selection-end-line="4" selection-end-column="66" />
<folding>
<marker date="1536884362681" expanded="true" signature="1034:1527" ph="{...}" />
<marker date="1536884362681" expanded="true" signature="1082:1150" ph="{...}" />
<marker date="1536884362681" expanded="true" signature="1196:1263" ph="{...}" />
<marker date="1536884362681" expanded="true" signature="1339:1427" ph="{...}" />
<marker date="1536884362681" expanded="true" signature="1459:1522" ph="{...}" />
<marker date="1536884362681" expanded="true" signature="1519:1522" ph="{...}" />
<marker date="1536884362681" expanded="true" signature="9770:9803" ph="{...}" />
<marker date="1536884362681" expanded="true" signature="9922:9954" ph="{...}" />
<marker date="1536884362681" expanded="true" signature="10114:10146" ph="{...}" />
<marker date="1536884362681" expanded="true" signature="10242:10267" ph="{...}" />
</folding>
</first_editor>
<second_editor />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="15">
<caret line="1" column="133" lean-forward="true" selection-start-line="1" selection-start-column="13" selection-end-line="1" selection-end-column="133" />
<folding />
</state>
</provider>
</entry>
</component>
</project>
\ No newline at end of file
## 0.0.1
Initial release.
/*
Copyright 2018 Lorenzo Pichilli
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
\ No newline at end of file
# Flutter InAppBrowser Plugin
[![Pub](https://img.shields.io/pub/v/flutter_inappbrowser.svg)](https://pub.dartlang.org/packages/flutter_inappbrowser)
A Flutter plugin that allows you to open an in-app browser window.
This plugin is a porting of the popular [cordova-plugin-inappbrowser](https://github.com/apache/cordova-plugin-inappbrowser)!
The Java/Swift code has been reshaped to work with the Flutter API.
## Getting Started
For help getting started with Flutter, view our online
[documentation](https://flutter.io/).
For help on editing plugin code, view the [documentation](https://flutter.io/developing-packages/#edit-plugin-package).
## Installation
First, add `flutter_inappbrowser` as a [dependency in your pubspec.yaml file](https://flutter.io/using-packages/).
## Usage
Create a Class that extends the `InAppBrowser` Class in order to override the callbacks to manage the browser events.
Example:
```dart
import 'package:flutter_inappbrowser/flutter_inappbrowser.dart';
class MyInAppBrowser extends InAppBrowser {
@override
void onLoadStart(String url) {
super.onLoadStart(url);
print("\n\nStarted $url\n\n");
}
@override
void onLoadStop(String url) {
super.onLoadStop(url);
print("\n\nStopped $url\n\n");
}
@override
void onLoadError(String url, String code, String message) {
super.onLoadStop(url);
print("\n\nCan't load $url.. Error: $message\n\n");
}
@override
void onExit() {
super.onExit();
print("\n\nBrowser closed!\n\n");
}
}
MyInAppBrowser inAppBrowser = new MyInAppBrowser();
```
### InAppBrowser.open
Opens a URL in a new InAppBrowser instance, the current browser instance, or the system browser.
```dart
inAppBrowser.open(url, target, options);
```
Opens an `url` in a new `InAppBrowser` instance or the system browser.
- `url`: The `url` to load __(String)__. Call [encodeUriComponent()] on this if the `url` contains Unicode characters.
- `target`: The target in which to load the `url`, an optional parameter that defaults to `_self`. __(String)__
- `_self`: Opens in the `InAppBrowser`.
- `_blank`: Opens in the `InAppBrowser`.
- `_system`: Opens in the system's web browser.
- `options`: Options for the `InAppBrowser`. Optional, defaulting to: `location=yes`. _(String)_
The `options` string must not contain any blank space, and each feature's name/value pairs must be separated by a comma. Feature names are case insensitive.
All platforms support:
- __location__: Set to `yes` or `no` to turn the `InAppBrowser`'s location bar on or off.
**Android** supports these additional options:
- __hidden__: set to `yes` to create the browser and load the page, but not show it. The loadstop event fires when loading is complete. Omit or set to `no` (default) to have the browser open and load normally.
- __clearcache__: set to `yes` to have the browser's cookie cache cleared before the new window is opened
- __clearsessioncache__: set to `yes` to have the session cookie cache cleared before the new window is opened
- __closebuttoncaption__: set to a string to use as the close button's caption instead of a X. Note that you need to localize this value yourself.
- __closebuttoncolor__: set to a valid hex color string, for example: `#00ff00`, and it will change the
close button color from default, regardless of being a text or default X. Only has effect if user has location set to `yes`.
- __footer__: set to `yes` to show a close button in the footer similar to the iOS __Done__ button.
The close button will appear the same as for the header hence use __closebuttoncaption__ and __closebuttoncolor__ to set its properties.
- __footercolor__: set to a valid hex color string, for example `#00ff00` or `#CC00ff00` (`#aarrggbb`) , and it will change the footer color from default.
Only has effect if user has __footer__ set to `yes`.
- __hardwareback__: set to `yes` to use the hardware back button to navigate backwards through the `InAppBrowser`'s history. If there is no previous page, the `InAppBrowser` will close. The default value is `yes`, so you must set it to `no` if you want the back button to simply close the InAppBrowser.
- __hidenavigationbuttons__: set to `yes` to hide the navigation buttons on the location toolbar, only has effect if user has location set to `yes`. The default value is `no`.
- __hideurlbar__: set to `yes` to hide the url bar on the location toolbar, only has effect if user has location set to `yes`. The default value is `no`.
- __navigationbuttoncolor__: set to a valid hex color string, for example: `#00ff00`, and it will change the color of both navigation buttons from default. Only has effect if user has location set to `yes` and not hidenavigationbuttons set to `yes`.
- __toolbarcolor__: set to a valid hex color string, for example: `#00ff00`, and it will change the color the toolbar from default. Only has effect if user has location set to `yes`.
- __zoom__: set to `yes` to show Android browser's zoom controls, set to `no` to hide them. Default value is `yes`.
- __mediaPlaybackRequiresUserAction__: Set to `yes` to prevent HTML5 audio or video from autoplaying (defaults to `no`).
- __shouldPauseOnSuspend__: Set to `yes` to make InAppBrowser WebView to pause/resume with the app to stop background audio (this may be required to avoid Google Play issues like described in [CB-11013](https://issues.apache.org/jira/browse/CB-11013)).
- __useWideViewPort__: Sets whether the WebView should enable support for the "viewport" HTML meta tag or should use a wide viewport. When the value of the setting is `no`, the layout width is always set to the width of the WebView control in device-independent (CSS) pixels. When the value is `yes` and the page contains the viewport meta tag, the value of the width specified in the tag is used. If the page does not contain the tag or does not provide a width, then a wide viewport will be used. (defaults to `yes`).
**iOS** supports these additional options:
- __hidden__: set to `yes` to create the browser and load the page, but not show it. The loadstop event fires when loading is complete. Omit or set to `no` (default) to have the browser open and load normally.
- __clearcache__: set to `yes` to have the browser's cookie cache cleared before the new window is opened
- __clearsessioncache__: set to `yes` to have the session cookie cache cleared before the new window is opened
- __closebuttoncolor__: set as a valid hex color string, for example: `#00ff00`, to change from the default __Done__ button's color. Only applicable if toolbar is not disabled.
- __closebuttoncaption__: set to a string to use as the __Done__ button's caption. Note that you need to localize this value yourself.
- __disallowoverscroll__: Set to `yes` or `no` (default is `no`). Turns on/off the UIWebViewBounce property.
- __hidenavigationbuttons__: set to `yes` or `no` to turn the toolbar navigation buttons on or off (defaults to `no`). Only applicable if toolbar is not disabled.
- __navigationbuttoncolor__: set as a valid hex color string, for example: `#00ff00`, to change from the default color. Only applicable if navigation buttons are visible.
- __toolbar__: set to `yes` or `no` to turn the toolbar on or off for the InAppBrowser (defaults to `yes`)
- __toolbarcolor__: set as a valid hex color string, for example: `#00ff00`, to change from the default color of the toolbar. Only applicable if toolbar is not disabled.
- __toolbartranslucent__: set to `yes` or `no` to make the toolbar translucent(semi-transparent) (defaults to `yes`). Only applicable if toolbar is not disabled.
- __enableViewportScale__: Set to `yes` or `no` to prevent viewport scaling through a meta tag (defaults to `no`).
- __mediaPlaybackRequiresUserAction__: Set to `yes` to prevent HTML5 audio or video from autoplaying (defaults to `no`).
- __allowInlineMediaPlayback__: Set to `yes` or `no` to allow in-line HTML5 media playback, displaying within the browser window rather than a device-specific playback interface. The HTML's `video` element must also include the `webkit-playsinline` attribute (defaults to `no`)
- __keyboardDisplayRequiresUserAction__: Set to `yes` or `no` to open the keyboard when form elements receive focus via JavaScript's `focus()` call (defaults to `yes`).
- __suppressesIncrementalRendering__: Set to `yes` or `no` to wait until all new view content is received before being rendered (defaults to `no`).
- __presentationstyle__: Set to `pagesheet`, `formsheet` or `fullscreen` to set the [presentation style](http://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instp/UIViewController/modalPresentationStyle) (defaults to `fullscreen`).
- __transitionstyle__: Set to `fliphorizontal`, `crossdissolve` or `coververtical` to set the [transition style](http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instp/UIViewController/modalTransitionStyle) (defaults to `coververtical`).
- __toolbarposition__: Set to `top` or `bottom` (default is `bottom`). Causes the toolbar to be at the top or bottom of the window.
- __hidespinner__: Set to `yes` or `no` to change the visibility of the loading indicator (defaults to `no`).
Example:
```dart
inAppBrowser.open('https://flutter.io/', '_blank', 'location=yes,hideurlbar=yes');
inAppBrowser.open('https://www.google.com/', '_blank', 'location=yes,toolbarposition=top,disallowoverscroll=yes');
```
### Events
Event fires when the `InAppBrowser` starts to load an `url`.
```dart
@override
void onLoadStart(String url) {
super.onLoadStart(url);
}
```
Event fires when the `InAppBrowser` finishes loading an `url`.
```dart
@override
void onLoadStop(String url) {
super.onLoadStop(url);
}
```
Event fires when the `InAppBrowser` encounters an error loading an `url`.
```dart
@override
void onLoadError(String url, String code, String message) {
super.onLoadStop(url);
}
```
Event fires when the `InAppBrowser` window is closed.
```dart
@override
void onExit() {
super.onExit();
}
```
### InAppBrowser.show
Displays an `InAppBrowser` window that was opened hidden. Calling this has no effect if the `InAppBrowser` was already visible.
Example:
```dart
inAppBrowser.show();
```
### InAppBrowser.hide
Hides the `InAppBrowser` window. Calling this has no effect if the `InAppBrowser` was already hidden.
Example:
```dart
inAppBrowser.hide();
```
### InAppBrowser.close
Closes the`InAppBrowser` window.
Example:
```dart
inAppBrowser.close();
```
### InAppBrowser.injectScriptCode
Injects JavaScript code into the `InAppBrowser` window. (Only available when the target is set to `_blank` or to `_self`)
Example:
```dart
inAppBrowser.injectScriptCode("""
alert("JavaScript injected");
""");
```
### InAppBrowser.injectScriptFile
Injects a JavaScript file into the `InAppBrowser` window. (Only available when the target is set to `_blank` or to `_self`)
Example:
```dart
inAppBrowser.injectScriptFile("https://code.jquery.com/jquery-3.3.1.min.js");
inAppBrowser.injectScriptCode("""
\$( "body" ).html( "Next Step..." )
""");
```
### InAppBrowser.injectStyleCode
Injects CSS into the `InAppBrowser` window. (Only available when the target is set to `_blank` or to `_self`)
Example:
```dart
inAppBrowser.injectStyleCode("""
body {
background-color: #3c3c3c;
}
""");
```
### InAppBrowser.injectStyleFile
Injects a CSS file into the `InAppBrowser` window. (Only available when the target is set to `_blank` or to `_self`)
Example:
```dart
inAppBrowser.injectStyleFile("https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css");
```
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
group 'com.pichillilorenzo.flutter_inappbrowser'
version '1.0-SNAPSHOT'
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.2'
}
}
rootProject.allprojects {
repositories {
google()
jcenter()
}
}
apply plugin: 'com.android.library'
android {
compileSdkVersion 27
defaultConfig {
minSdkVersion 16
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
lintOptions {
disable 'InvalidPackage'
}
}
org.gradle.jvmargs=-Xmx1536M
rootProject.name = 'flutter_inappbrowser'
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.pichillilorenzo.flutter_inappbrowser">
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package com.pichillilorenzo.flutter_inappbrowser;
import android.annotation.TargetApi;
import android.app.Activity;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.provider.Browser;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.text.InputType;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.webkit.CookieManager;
import android.webkit.MimeTypeMap;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Arrays;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.Registrar;
/** InAppBrowser */
public class InAppBrowser implements MethodCallHandler {
private Registrar registrar;
private Activity activity;
private final MethodChannel channel;
private static final String NULL = "null";
protected static final String LOG_TAG = "InAppBrowser";
private static final String SELF = "_self";
private static final String SYSTEM = "_system";
private static final String EXIT_EVENT = "exit";
private static final String LOCATION = "location";
private static final String ZOOM = "zoom";
private static final String HIDDEN = "hidden";
private static final String CLEAR_ALL_CACHE = "clearcache";
private static final String CLEAR_SESSION_CACHE = "clearsessioncache";
private static final String HARDWARE_BACK_BUTTON = "hardwareback";
private static final String MEDIA_PLAYBACK_REQUIRES_USER_ACTION = "mediaPlaybackRequiresUserAction";
private static final String SHOULD_PAUSE = "shouldPauseOnSuspend";
private static final Boolean DEFAULT_HARDWARE_BACK = true;
private static final String USER_WIDE_VIEW_PORT = "useWideViewPort";
private static final String TOOLBAR_COLOR = "toolbarcolor";
private static final String CLOSE_BUTTON_CAPTION = "closebuttoncaption";
private static final String CLOSE_BUTTON_COLOR = "closebuttoncolor";
private static final String HIDE_NAVIGATION = "hidenavigationbuttons";
private static final String NAVIGATION_COLOR = "navigationbuttoncolor";
private static final String HIDE_URL = "hideurlbar";
private static final String FOOTER = "footer";
private static final String FOOTER_COLOR = "footercolor";
private static final List customizableOptions = Arrays.asList(CLOSE_BUTTON_CAPTION, TOOLBAR_COLOR, NAVIGATION_COLOR, CLOSE_BUTTON_COLOR, FOOTER_COLOR);
private InAppBrowserDialog dialog;
private WebView inAppWebView;
private EditText edittext;
private boolean showLocationBar = true;
private boolean showZoomControls = true;
private boolean openWindowHidden = false;
private boolean clearAllCache = false;
private boolean clearSessionCache = false;
private boolean hadwareBackButton = true;
private boolean mediaPlaybackRequiresUserGesture = false;
private boolean shouldPauseInAppBrowser = false;
private boolean useWideViewPort = true;
private ValueCallback<Uri> mUploadCallback;
private ValueCallback<Uri[]> mUploadCallbackLollipop;
private final static int FILECHOOSER_REQUESTCODE = 1;
private final static int FILECHOOSER_REQUESTCODE_LOLLIPOP = 2;
private String closeButtonCaption = "";
private String closeButtonColor = "";
private int toolbarColor = android.graphics.Color.LTGRAY;
private boolean hideNavigationButtons = false;
private String navigationButtonColor = "";
private boolean hideUrlBar = false;
private boolean showFooter = false;
private String footerColor = "";
private String[] allowedSchemes;
public InAppBrowser(Registrar registrar, Activity activity) {
this.registrar = registrar;
this.activity = activity;
this.channel = new MethodChannel(registrar.messenger(), "com.pichillilorenzo/flutter_inappbrowser");
}
/** Plugin registration. */
public static void registerWith(Registrar registrar) {
final MethodChannel channel = new MethodChannel(registrar.messenger(), "com.pichillilorenzo/flutter_inappbrowser");
channel.setMethodCallHandler(new InAppBrowser(registrar, registrar.activity()));
}
@Override
public void onMethodCall(MethodCall call, final Result result) {
String source;
String jsWrapper;
String urlFile;
switch (call.method) {
case "open":
final String url = call.argument("url").toString();
String t = call.argument("target").toString();
if (t == null || t.equals("") || t.equals(NULL)) {
t = SELF;
}
final String target = t;
final HashMap<String, String> features = parseFeature(call.argument("options").toString());
Log.d(LOG_TAG, "target = " + target);
this.activity.runOnUiThread(new Runnable() {
@Override
public void run() {
String r = "";
// SELF
if (SELF.equals(target)) {
Log.d(LOG_TAG, "in self");
//Load the dialer
if (url.startsWith(WebView.SCHEME_TEL))
{
try {
Log.d(LOG_TAG, "loading in dialer");
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse(url));
activity.startActivity(intent);
} catch (android.content.ActivityNotFoundException e) {
Log.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
}
}
// load in InAppBrowser
else {
Log.d(LOG_TAG, "loading in InAppBrowser");
r = showWebPage(url, features);
}
}
// SYSTEM
else if (SYSTEM.equals(target)) {
Log.d(LOG_TAG, "in system");
r = openExternal(url);
}
// BLANK - or anything else
else {
Log.d(LOG_TAG, "in blank");
r = showWebPage(url, features);
}
result.success(r);
}
});
break;
case "close":
closeDialog();
result.success(true);
break;
case "injectScriptCode":
source = call.argument("source").toString();
jsWrapper = "(function(){JSON.stringify([eval(%s)])})()";
injectDeferredObject(source, jsWrapper);
result.success(true);
break;
case "injectScriptFile":
urlFile = call.argument("urlFile").toString();
jsWrapper = "(function(d) { var c = d.createElement('script'); c.src = %s; d.body.appendChild(c); })(document)";
injectDeferredObject(urlFile, jsWrapper);
result.success(true);
break;
case "injectStyleCode":
source = call.argument("source").toString();
jsWrapper = "(function(d) { var c = d.createElement('style'); c.innerHTML = %s; d.body.appendChild(c); })(document)";
injectDeferredObject(source, jsWrapper);
result.success(true);
break;
case "injectStyleFile":
urlFile = call.argument("urlFile").toString();
jsWrapper = "(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %s; d.head.appendChild(c); })(document)";
injectDeferredObject(urlFile, jsWrapper);
result.success(true);
break;
case "show":
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
dialog.show();
}
});
result.success(true);
break;
case "hide":
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
dialog.hide();
}
});
result.success(true);
break;
default:
result.notImplemented();
}
}
/**
* Inject an object (script or style) into the InAppBrowser WebView.
*
* This is a helper method for the inject{Script|Style}{Code|File} API calls, which
* provides a consistent method for injecting JavaScript code into the document.
*
* If a wrapper string is supplied, then the source string will be JSON-encoded (adding
* quotes) and wrapped using string formatting. (The wrapper string should have a single
* '%s' marker)
*
* @param source The source object (filename or script/style text) to inject into
* the document.
* @param jsWrapper A JavaScript string to wrap the source string in, so that the object
* is properly injected, or null if the source string is JavaScript text
* which should be executed directly.
*/
private void injectDeferredObject(String source, String jsWrapper) {
if (inAppWebView!=null) {
String scriptToInject;
if (jsWrapper != null) {
org.json.JSONArray jsonEsc = new org.json.JSONArray();
jsonEsc.put(source);
String jsonRepr = jsonEsc.toString();
String jsonSourceString = jsonRepr.substring(1, jsonRepr.length()-1);
scriptToInject = String.format(jsWrapper, jsonSourceString);
} else {
scriptToInject = source;
}
final String finalScriptToInject = scriptToInject;
activity.runOnUiThread(new Runnable() {
@SuppressLint("NewApi")
@Override
public void run() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
// This action will have the side-effect of blurring the currently focused element
inAppWebView.loadUrl("javascript:" + finalScriptToInject);
} else {
inAppWebView.evaluateJavascript(finalScriptToInject, null);
}
}
});
} else {
Log.d(LOG_TAG, "Can't inject code into the system browser");
}
}
public static String getMimeType(String url) {
String type = null;
String extension = MimeTypeMap.getFileExtensionFromUrl(url);
if (extension != null) {
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}
return type;
}
/**
* Display a new browser with the specified URL.
*
* @param url the url to load.
* @return "" if ok, or error message.
*/
public String openExternal(String url) {
try {
Intent intent = null;
intent = new Intent(Intent.ACTION_VIEW);
// Omitting the MIME type for file: URLs causes "No Activity found to handle Intent".
// Adding the MIME type to http: URLs causes them to not be handled by the downloader.
Uri uri = Uri.parse(url);
if ("file".equals(uri.getScheme())) {
intent.setDataAndType(uri, getMimeType(url));
} else {
intent.setData(uri);
}
intent.putExtra(Browser.EXTRA_APPLICATION_ID, activity.getPackageName());
activity.startActivity(intent);
return "";
// not catching FileUriExposedException explicitly because buildtools<24 doesn't know about it
} catch (java.lang.RuntimeException e) {
Log.d(LOG_TAG, "InAppBrowser: Error loading url "+url+":"+ e.toString());
return e.toString();
}
}
@TargetApi(8)
private String showWebPage(final String url, HashMap<String, String> features) {
// Determine if we should hide the location bar.
showLocationBar = true;
showZoomControls = true;
openWindowHidden = false;
mediaPlaybackRequiresUserGesture = false;
if (features != null) {
String show = features.get(LOCATION);
if (show != null) {
showLocationBar = show.equals("yes") ? true : false;
}
if(showLocationBar) {
String hideNavigation = features.get(HIDE_NAVIGATION);
String hideUrl = features.get(HIDE_URL);
if(hideNavigation != null) hideNavigationButtons = hideNavigation.equals("yes") ? true : false;
if(hideUrl != null) hideUrlBar = hideUrl.equals("yes") ? true : false;
}
String zoom = features.get(ZOOM);
if (zoom != null) {
showZoomControls = zoom.equals("yes") ? true : false;
}
String hidden = features.get(HIDDEN);
if (hidden != null) {
openWindowHidden = hidden.equals("yes") ? true : false;
}
String hardwareBack = features.get(HARDWARE_BACK_BUTTON);
if (hardwareBack != null) {
hadwareBackButton = hardwareBack.equals("yes") ? true : false;
} else {
hadwareBackButton = DEFAULT_HARDWARE_BACK;
}
String mediaPlayback = features.get(MEDIA_PLAYBACK_REQUIRES_USER_ACTION);
if (mediaPlayback != null) {
mediaPlaybackRequiresUserGesture = mediaPlayback.equals("yes") ? true : false;
}
String cache = features.get(CLEAR_ALL_CACHE);
if (cache != null) {
clearAllCache = cache.equals("yes") ? true : false;
} else {
cache = features.get(CLEAR_SESSION_CACHE);
if (cache != null) {
clearSessionCache = cache.equals("yes") ? true : false;
}
}
String shouldPause = features.get(SHOULD_PAUSE);
if (shouldPause != null) {
shouldPauseInAppBrowser = shouldPause.equals("yes") ? true : false;
}
String wideViewPort = features.get(USER_WIDE_VIEW_PORT);
if (wideViewPort != null ) {
useWideViewPort = wideViewPort.equals("yes") ? true : false;
}
String closeButtonCaptionSet = features.get(CLOSE_BUTTON_CAPTION);
if (closeButtonCaptionSet != null) {
closeButtonCaption = closeButtonCaptionSet;
}
String closeButtonColorSet = features.get(CLOSE_BUTTON_COLOR);
if (closeButtonColorSet != null) {
closeButtonColor = closeButtonColorSet;
}
String toolbarColorSet = features.get(TOOLBAR_COLOR);
if (toolbarColorSet != null) {
toolbarColor = android.graphics.Color.parseColor(toolbarColorSet);
}
String navigationButtonColorSet = features.get(NAVIGATION_COLOR);
if (navigationButtonColorSet != null) {
navigationButtonColor = navigationButtonColorSet;
}
String showFooterSet = features.get(FOOTER);
if (showFooterSet != null) {
showFooter = showFooterSet.equals("yes") ? true : false;
}
String footerColorSet = features.get(FOOTER_COLOR);
if (footerColorSet != null) {
footerColor = footerColorSet;
}
}
// Create dialog in new thread
Runnable runnable = new Runnable() {
/**
* Convert our DIP units to Pixels
*
* @return int
*/
private int dpToPixels(int dipValue) {
int value = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP,
(float) dipValue,
activity.getResources().getDisplayMetrics()
);
return value;
}
@TargetApi(8)
private View createCloseButton(int id){
View _close;
Resources activityRes = activity.getResources();
if (closeButtonCaption != "") {
// Use TextView for text
TextView close = new TextView(activity);
close.setText(closeButtonCaption);
close.setTextSize(20);
if (closeButtonColor != "") close.setTextColor(android.graphics.Color.parseColor(closeButtonColor));
close.setGravity(android.view.Gravity.CENTER_VERTICAL);
close.setPadding(this.dpToPixels(10), 0, this.dpToPixels(10), 0);
_close = close;
}
else {
ImageButton close = new ImageButton(activity);
int closeResId = activityRes.getIdentifier("ic_action_remove", "drawable", activity.getPackageName());
Drawable closeIcon = activityRes.getDrawable(closeResId);
if (closeButtonColor != "") close.setColorFilter(android.graphics.Color.parseColor(closeButtonColor));
close.setImageDrawable(closeIcon);
close.setScaleType(ImageView.ScaleType.FIT_CENTER);
if (Build.VERSION.SDK_INT >= 16)
close.getAdjustViewBounds();
_close = close;
}
RelativeLayout.LayoutParams closeLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
closeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
_close.setLayoutParams(closeLayoutParams);
if (Build.VERSION.SDK_INT >= 16)
_close.setBackground(null);
else
_close.setBackgroundDrawable(null);
_close.setContentDescription("Close Button");
_close.setId(Integer.valueOf(id));
_close.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
closeDialog();
}
});
return _close;
}
@SuppressLint("NewApi")
public void run() {
// CB-6702 InAppBrowser hangs when opening more than one instance
if (dialog != null) {
dialog.dismiss();
};
// Let's create the main dialog
dialog = new InAppBrowserDialog(activity, android.R.style.Theme_NoTitleBar);
dialog.getWindow().getAttributes().windowAnimations = android.R.style.Animation_Dialog;
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setCancelable(true);
dialog.setInAppBroswer(getInAppBrowser());
// Main container layout
LinearLayout main = new LinearLayout(activity);
main.setOrientation(LinearLayout.VERTICAL);
// Toolbar layout
RelativeLayout toolbar = new RelativeLayout(activity);
//Please, no more black!
toolbar.setBackgroundColor(toolbarColor);
toolbar.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, this.dpToPixels(44)));
toolbar.setPadding(this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2));
toolbar.setHorizontalGravity(Gravity.LEFT);
toolbar.setVerticalGravity(Gravity.TOP);
// Action Button Container layout
RelativeLayout actionButtonContainer = new RelativeLayout(activity);
actionButtonContainer.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
actionButtonContainer.setHorizontalGravity(Gravity.LEFT);
actionButtonContainer.setVerticalGravity(Gravity.CENTER_VERTICAL);
actionButtonContainer.setId(Integer.valueOf(1));
// Back button
ImageButton back = new ImageButton(activity);
RelativeLayout.LayoutParams backLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
backLayoutParams.addRule(RelativeLayout.ALIGN_LEFT);
back.setLayoutParams(backLayoutParams);
back.setContentDescription("Back Button");
back.setId(Integer.valueOf(2));
Resources activityRes = activity.getResources();
int backResId = activityRes.getIdentifier("ic_action_previous_item", "drawable", activity.getPackageName());
Drawable backIcon = activityRes.getDrawable(backResId);
if (navigationButtonColor != "") back.setColorFilter(android.graphics.Color.parseColor(navigationButtonColor));
if (Build.VERSION.SDK_INT >= 16)
back.setBackground(null);
else
back.setBackgroundDrawable(null);
back.setImageDrawable(backIcon);
back.setScaleType(ImageView.ScaleType.FIT_CENTER);
back.setPadding(0, this.dpToPixels(10), 0, this.dpToPixels(10));
if (Build.VERSION.SDK_INT >= 16)
back.getAdjustViewBounds();
back.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
goBack();
}
});
// Forward button
ImageButton forward = new ImageButton(activity);
RelativeLayout.LayoutParams forwardLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
forwardLayoutParams.addRule(RelativeLayout.RIGHT_OF, 2);
forward.setLayoutParams(forwardLayoutParams);
forward.setContentDescription("Forward Button");
forward.setId(Integer.valueOf(3));
int fwdResId = activityRes.getIdentifier("ic_action_next_item", "drawable", activity.getPackageName());
Drawable fwdIcon = activityRes.getDrawable(fwdResId);
if (navigationButtonColor != "") forward.setColorFilter(android.graphics.Color.parseColor(navigationButtonColor));
if (Build.VERSION.SDK_INT >= 16)
forward.setBackground(null);
else
forward.setBackgroundDrawable(null);
forward.setImageDrawable(fwdIcon);
forward.setScaleType(ImageView.ScaleType.FIT_CENTER);
forward.setPadding(0, this.dpToPixels(10), 0, this.dpToPixels(10));
if (Build.VERSION.SDK_INT >= 16)
forward.getAdjustViewBounds();
forward.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
goForward();
}
});
// Edit Text Box
edittext = new EditText(activity);
RelativeLayout.LayoutParams textLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
textLayoutParams.addRule(RelativeLayout.RIGHT_OF, 1);
textLayoutParams.addRule(RelativeLayout.LEFT_OF, 5);
edittext.setLayoutParams(textLayoutParams);
edittext.setId(Integer.valueOf(4));
edittext.setSingleLine(true);
edittext.setText(url);
edittext.setInputType(InputType.TYPE_TEXT_VARIATION_URI);
edittext.setImeOptions(EditorInfo.IME_ACTION_GO);
edittext.setInputType(InputType.TYPE_NULL); // Will not except input... Makes the text NON-EDITABLE
edittext.setOnKeyListener(new View.OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
// If the event is a key-down event on the "enter" button
if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {
navigate(edittext.getText().toString());
return true;
}
return false;
}
});
// Header Close/Done button
View close = createCloseButton(5);
toolbar.addView(close);
// Footer
RelativeLayout footer = new RelativeLayout(activity);
int _footerColor;
if(footerColor != ""){
_footerColor = Color.parseColor(footerColor);
}else{
_footerColor = android.graphics.Color.LTGRAY;
}
footer.setBackgroundColor(_footerColor);
RelativeLayout.LayoutParams footerLayout = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, this.dpToPixels(44));
footerLayout.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
footer.setLayoutParams(footerLayout);
if (closeButtonCaption != "") footer.setPadding(this.dpToPixels(8), this.dpToPixels(8), this.dpToPixels(8), this.dpToPixels(8));
footer.setHorizontalGravity(Gravity.LEFT);
footer.setVerticalGravity(Gravity.BOTTOM);
View footerClose = createCloseButton(7);
footer.addView(footerClose);
// WebView
inAppWebView = new WebView(activity);
inAppWebView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
inAppWebView.setId(Integer.valueOf(6));
inAppWebView.setWebChromeClient(new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
}
@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
}
@Override
public void onReceivedIcon(WebView view, Bitmap icon) {
super.onReceivedIcon(view, icon);
}
// For Android 5.0+
public boolean onShowFileChooser (WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams)
{
Log.d(LOG_TAG, "File Chooser 5.0+");
// If callback exists, finish it.
if(mUploadCallbackLollipop != null) {
mUploadCallbackLollipop.onReceiveValue(null);
}
mUploadCallbackLollipop = filePathCallback;
// Create File Chooser Intent
Intent content = new Intent(Intent.ACTION_GET_CONTENT);
content.addCategory(Intent.CATEGORY_OPENABLE);
content.setType("*/*");
registrar.context().startActivity(Intent.createChooser(content, "Select File"));
return true;
}
// For Android 4.1+
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture)
{
Log.d(LOG_TAG, "File Chooser 4.1+");
// Call file chooser for Android 3.0+
openFileChooser(uploadMsg, acceptType);
}
// For Android 3.0+
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType)
{
Log.d(LOG_TAG, "File Chooser 3.0+");
mUploadCallback = uploadMsg;
Intent content = new Intent(Intent.ACTION_GET_CONTENT);
content.addCategory(Intent.CATEGORY_OPENABLE);
registrar.context().startActivity(Intent.createChooser(content, "Select File"));
}
});
WebViewClient client = new InAppBrowserClient(edittext, activity, channel);
inAppWebView.setWebViewClient(client);
WebSettings settings = inAppWebView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setJavaScriptCanOpenWindowsAutomatically(true);
settings.setBuiltInZoomControls(showZoomControls);
settings.setPluginState(android.webkit.WebSettings.PluginState.ON);
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
settings.setMediaPlaybackRequiresUserGesture(mediaPlaybackRequiresUserGesture);
}
String overrideUserAgent = activity.getPreferences(0).getString("OverrideUserAgent", null);
String appendUserAgent = activity.getPreferences(0).getString("AppendUserAgent", null);
if (overrideUserAgent != null) {
settings.setUserAgentString(overrideUserAgent);
}
if (appendUserAgent != null) {
settings.setUserAgentString(settings.getUserAgentString() + appendUserAgent);
}
//Toggle whether this is enabled or not!
Bundle appSettings = activity.getIntent().getExtras();
boolean enableDatabase = appSettings == null ? true : appSettings.getBoolean("InAppBrowserStorageEnabled", true);
if (enableDatabase) {
String databasePath = activity.getApplicationContext().getDir("inAppBrowserDB", Context.MODE_PRIVATE).getPath();
settings.setDatabasePath(databasePath);
settings.setDatabaseEnabled(true);
}
settings.setDomStorageEnabled(true);
if (clearAllCache) {
CookieManager.getInstance().removeAllCookie();
} else if (clearSessionCache) {
CookieManager.getInstance().removeSessionCookie();
}
// Enable Thirdparty Cookies on >=Android 5.0 device
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
CookieManager.getInstance().setAcceptThirdPartyCookies(inAppWebView,true);
}
inAppWebView.loadUrl(url);
inAppWebView.setId(Integer.valueOf(6));
inAppWebView.getSettings().setLoadWithOverviewMode(true);
inAppWebView.getSettings().setUseWideViewPort(useWideViewPort);
inAppWebView.requestFocus();
inAppWebView.requestFocusFromTouch();
// Add the back and forward buttons to our action button container layout
actionButtonContainer.addView(back);
actionButtonContainer.addView(forward);
// Add the views to our toolbar if they haven't been disabled
if (!hideNavigationButtons) toolbar.addView(actionButtonContainer);
if (!hideUrlBar) toolbar.addView(edittext);
// Don't add the toolbar if its been disabled
if (getShowLocationBar()) {
// Add our toolbar to our main view/layout
main.addView(toolbar);
}
// Add our webview to our main view/layout
RelativeLayout webViewLayout = new RelativeLayout(activity);
webViewLayout.addView(inAppWebView);
main.addView(webViewLayout);
// Don't add the footer unless it's been enabled
if (showFooter) {
webViewLayout.addView(footer);
}
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.copyFrom(dialog.getWindow().getAttributes());
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
lp.height = WindowManager.LayoutParams.MATCH_PARENT;
dialog.setContentView(main);
dialog.show();
dialog.getWindow().setAttributes(lp);
// the goal of openhidden is to load the url and not display it
// Show() needs to be called to cause the URL to be loaded
if(openWindowHidden) {
dialog.hide();
}
}
};
this.activity.runOnUiThread(runnable);
return "";
}
/**
* Put the list of features into a hash map
*
* @param optString
* @return
*/
private HashMap<String, String> parseFeature(String optString) {
if (optString.equals(NULL)) {
return null;
} else {
HashMap<String, String> map = new HashMap<String, String>();
StringTokenizer features = new StringTokenizer(optString, ",");
StringTokenizer option;
while(features.hasMoreElements()) {
option = new StringTokenizer(features.nextToken(), "=");
if (option.hasMoreElements()) {
String key = option.nextToken();
String value = option.nextToken();
if (!customizableOptions.contains(key)){
value = value.equals("yes") || value.equals("no") ? value : "yes";
}
map.put(key, value);
}
}
return map;
}
}
/**
* Checks to see if it is possible to go back one page in history, then does so.
*/
public void goBack() {
if (this.inAppWebView.canGoBack()) {
this.inAppWebView.goBack();
}
}
/**
* Can the web browser go back?
* @return boolean
*/
public boolean canGoBack() {
return this.inAppWebView.canGoBack();
}
/**
* Has the user set the hardware back button to go back
* @return boolean
*/
public boolean hardwareBack() {
return hadwareBackButton;
}
/**
* Checks to see if it is possible to go forward one page in history, then does so.
*/
private void goForward() {
if (this.inAppWebView.canGoForward()) {
this.inAppWebView.goForward();
}
}
/**
* Navigate to the new page
*
* @param url to load
*/
@TargetApi(3)
private void navigate(String url) {
InputMethodManager imm = (InputMethodManager)this.activity.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(edittext.getWindowToken(), 0);
if (!url.startsWith("http") && !url.startsWith("file:")) {
this.inAppWebView.loadUrl("http://" + url);
} else {
this.inAppWebView.loadUrl(url);
}
this.inAppWebView.requestFocus();
}
/**
* Should we show the location bar?
*
* @return boolean
*/
private boolean getShowLocationBar() {
return this.showLocationBar;
}
private InAppBrowser getInAppBrowser(){
return this;
}
/**
* Closes the dialog
*/
public void closeDialog() {
this.activity.runOnUiThread(new Runnable() {
@Override
public void run() {
final WebView childView = inAppWebView;
// The JS protects against multiple calls, so this should happen only when
// closeDialog() is called by other native code.
if (childView == null) {
return;
}
childView.setWebViewClient(new WebViewClient() {
// NB: wait for about:blank before dismissing
public void onPageFinished(WebView view, String url) {
if (dialog != null) {
dialog.dismiss();
dialog = null;
}
}
});
// NB: From SDK 19: "If you call methods on WebView from any thread
// other than your app's UI thread, it can cause unexpected results."
// http://developer.android.com/guide/webapps/migrating.html#Threads
childView.loadUrl("about:blank");
Map<String, Object> obj = new HashMap<>();
obj.put("type", EXIT_EVENT);
channel.invokeMethod(EXIT_EVENT, obj);
}
});
}
/**
* Called by AccelBroker when listener is to be shut down.
* Stop listener.
*/
public void onDestroy() {
closeDialog();
}
}
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package com.pichillilorenzo.flutter_inappbrowser;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import android.webkit.HttpAuthHandler;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.EditText;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
import io.flutter.plugin.common.MethodChannel;
/**
* The webview client receives notifications about appView
*/
public class InAppBrowserClient extends WebViewClient {
protected static final String LOG_TAG = "InAppBrowser";
private static final String LOAD_START_EVENT = "loadstart";
private static final String LOAD_STOP_EVENT = "loadstop";
private static final String LOAD_ERROR_EVENT = "loaderror";
private String[] allowedSchemes;
private EditText edittext;
private Activity activity;
private final MethodChannel channel;
/**
* Constructor.
*
* @param mEditText
* @param activity
*/
public InAppBrowserClient(EditText mEditText, Activity activity, MethodChannel channel) {
this.edittext = mEditText;
this.activity = activity;
this.channel = channel;
}
/**
* Override the URL that should be loaded
*
* This handles a small subset of all the URIs that would be encountered.
*
* @param webView
* @param url
*/
@Override
public boolean shouldOverrideUrlLoading(WebView webView, String url) {
if (url.startsWith(WebView.SCHEME_TEL)) {
try {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse(url));
activity.startActivity(intent);
return true;
} catch (android.content.ActivityNotFoundException e) {
Log.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
}
} else if (url.startsWith("geo:") || url.startsWith(WebView.SCHEME_MAILTO) || url.startsWith("market:") || url.startsWith("intent:")) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
activity.startActivity(intent);
return true;
} catch (android.content.ActivityNotFoundException e) {
Log.e(LOG_TAG, "Error with " + url + ": " + e.toString());
}
}
// If sms:5551212?body=This is the message
else if (url.startsWith("sms:")) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
// Get address
String address = null;
int parmIndex = url.indexOf('?');
if (parmIndex == -1) {
address = url.substring(4);
} else {
address = url.substring(4, parmIndex);
// If body, then set sms body
Uri uri = Uri.parse(url);
String query = uri.getQuery();
if (query != null) {
if (query.startsWith("body=")) {
intent.putExtra("sms_body", query.substring(5));
}
}
}
intent.setData(Uri.parse("sms:" + address));
intent.putExtra("address", address);
intent.setType("vnd.android-dir/mms-sms");
activity.startActivity(intent);
return true;
} catch (android.content.ActivityNotFoundException e) {
Log.e(LOG_TAG, "Error sending sms " + url + ":" + e.toString());
}
}
// Test for whitelisted custom scheme names like mycoolapp:// or twitteroauthresponse:// (Twitter Oauth Response)
else if (!url.startsWith("http:") && !url.startsWith("https:") && url.matches("^[A-Za-z0-9+.-]*://.*?$")) {
if (allowedSchemes == null) {
String allowed = activity.getPreferences(0).getString("AllowedSchemes", null);
if(allowed != null) {
allowedSchemes = allowed.split(",");
}
}
if (allowedSchemes != null) {
for (String scheme : allowedSchemes) {
if (url.startsWith(scheme)) {
Map<String, Object> obj = new HashMap<>();
obj.put("type", "customscheme");
obj.put("url", url);
channel.invokeMethod("customscheme", obj);
return true;
}
}
}
}
return false;
}
/*
* onPageStarted fires the LOAD_START_EVENT
*
* @param view
* @param url
* @param favicon
*/
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
String newloc = "";
if (url.startsWith("http:") || url.startsWith("https:") || url.startsWith("file:")) {
newloc = url;
}
else
{
// Assume that everything is HTTP at this point, because if we don't specify,
// it really should be. Complain loudly about this!!!
Log.e(LOG_TAG, "Possible Uncaught/Unknown URI");
newloc = "http://" + url;
}
// Update the UI if we haven't already
if (!newloc.equals(edittext.getText().toString())) {
edittext.setText(newloc);
}
Map<String, Object> obj = new HashMap<>();
obj.put("type", LOAD_START_EVENT);
obj.put("url", newloc);
channel.invokeMethod(LOAD_START_EVENT, obj);
}
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
// CB-10395 InAppBrowser's WebView not storing cookies reliable to local device storage
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
CookieManager.getInstance().flush();
} else {
CookieSyncManager.getInstance().sync();
}
// https://issues.apache.org/jira/browse/CB-11248
view.clearFocus();
view.requestFocus();
Map<String, Object> obj = new HashMap<>();
obj.put("type", LOAD_STOP_EVENT);
obj.put("url", url);
channel.invokeMethod(LOAD_STOP_EVENT, obj);
}
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
Map<String, Object> obj = new HashMap<>();
obj.put("type", LOAD_ERROR_EVENT);
obj.put("url", failingUrl);
obj.put("code", errorCode);
obj.put("message", description);
channel.invokeMethod(LOAD_ERROR_EVENT, obj);
}
/**
* On received http auth request.
*/
@Override
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
// By default handle 401 like we'd normally do!
super.onReceivedHttpAuthRequest(view, handler, host, realm);
}
}
\ No newline at end of file
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package com.pichillilorenzo.flutter_inappbrowser;
import android.app.Dialog;
import android.content.Context;
public class InAppBrowserDialog extends Dialog {
Context context;
InAppBrowser inAppBrowser = null;
public InAppBrowserDialog(Context context, int theme) {
super(context, theme);
this.context = context;
}
public void setInAppBroswer(InAppBrowser browser) {
this.inAppBrowser = browser;
}
public void onBackPressed () {
if (this.inAppBrowser == null) {
this.dismiss();
} else {
// better to go through the in inAppBrowser
// because it does a clean up
if (this.inAppBrowser.hardwareBack() && this.inAppBrowser.canGoBack()) {
this.inAppBrowser.goBack();
} else {
this.inAppBrowser.closeDialog();
}
}
}
}
\ No newline at end of file
# Miscellaneous
*.class
*.lock
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# Visual Studio Code related
.vscode/
# Flutter/Dart/Pub related
**/doc/api/
.dart_tool/
.flutter-plugins
.packages
.pub-cache/
.pub/
build/
# Android related
**/android/**/gradle-wrapper.jar
**/android/.gradle
**/android/captures/
**/android/gradlew
**/android/gradlew.bat
**/android/local.properties
**/android/**/GeneratedPluginRegistrant.java
# iOS/XCode related
**/ios/**/*.mode1v3
**/ios/**/*.mode2v3
**/ios/**/*.moved-aside
**/ios/**/*.pbxuser
**/ios/**/*.perspectivev3
**/ios/**/*sync/
**/ios/**/.sconsign.dblite
**/ios/**/.tags*
**/ios/**/.vagrant/
**/ios/**/DerivedData/
**/ios/**/Icon?
**/ios/**/Pods/
**/ios/**/.symlinks/
**/ios/**/profile
**/ios/**/xcuserdata
**/ios/.generated/
**/ios/Flutter/App.framework
**/ios/Flutter/Flutter.framework
**/ios/Flutter/Generated.xcconfig
**/ios/Flutter/app.flx
**/ios/Flutter/app.zip
**/ios/Flutter/flutter_assets/
**/ios/ServiceDefinitions.json
**/ios/Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!**/ios/**/default.mode1v3
!**/ios/**/default.mode2v3
!**/ios/**/default.pbxuser
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: d927c9331005f81157fa39dff7b5dab415ad330b
channel: master
# flutter_inappbrowser_example
Demonstrates how to use the flutter_inappbrowser plugin.
## Getting Started
For help getting started with Flutter, view our online
[documentation](https://flutter.io/).
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 27
lintOptions {
disable 'InvalidPackage'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.pichillilorenzo.flutter_inappbrowserexample"
minSdkVersion 16
targetSdkVersion 27
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
}
flutter {
source '../..'
}
dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.pichillilorenzo.flutter_inappbrowserexample">
<!-- The INTERNET permission is required for development. Specifically,
flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:name="io.flutter.app.FlutterApplication"
android:label="flutter_inappbrowser_example"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- This keeps the window background of the activity showing
until Flutter renders its first frame. It can be removed if
there is no splash screen (such as the default splash screen
defined in @style/LaunchTheme). -->
<meta-data
android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
android:value="true" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
package com.pichillilorenzo.flutter_inappbrowserexample;
import android.os.Bundle;
import io.flutter.app.FlutterActivity;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
}
}
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
</resources>
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.2'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}
org.gradle.jvmargs=-Xmx1536M
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
include ':app'
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
if (pluginsFile.exists()) {
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
}
plugins.each { name, path ->
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
include ":$name"
project(":$name").projectDir = pluginDirectory
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>8.0</string>
</dict>
</plist>
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
FLUTTER_BUILD_MODE=debug
\ No newline at end of file
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
def parse_KV_file(file, separator='=')
file_abs_path = File.expand_path(file)
if !File.exists? file_abs_path
return [];
end
pods_ary = []
skip_line_start_symbols = ["#", "/"]
File.foreach(file_abs_path) { |line|
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
plugin = line.split(pattern=separator)
if plugin.length == 2
podname = plugin[0].strip()
path = plugin[1].strip()
podpath = File.expand_path("#{path}", file_abs_path)
pods_ary.push({:name => podname, :path => podpath});
else
puts "Invalid plugin specification: #{line}"
end
}
return pods_ary
end
target 'Runner' do
use_frameworks!
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines.
system('rm -rf .symlinks')
system('mkdir -p .symlinks/plugins')
# Flutter Pods
generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
if generated_xcode_build_settings.empty?
puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first."
end
generated_xcode_build_settings.map { |p|
if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
symlink = File.join('.symlinks', 'flutter')
File.symlink(File.dirname(p[:path]), symlink)
pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
end
}
# Plugin Pods
plugin_pods = parse_KV_file('../.flutter-plugins')
plugin_pods.map { |p|
symlink = File.join('.symlinks', 'plugins', p[:name])
File.symlink(p[:path], symlink)
pod p[:name], :path => File.join(symlink, 'ios')
}
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.headers_build_phase.files.each do |file|
file.settings = { 'ATTRIBUTES' => ['Public'] }
end
target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'NO'
end
end
end
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
25A517508F43E58C47090625 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E8D91E403808A7540F18B75D /* Pods_Runner.framework */; };
2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
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>"; };
E8D91E403808A7540F18B75D /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
25A517508F43E58C47090625 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
50BAF1DF19E018DDF2B149B9 /* Frameworks */ = {
isa = PBXGroup;
children = (
E8D91E403808A7540F18B75D /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
647DC95AB5350DB6D2264FFE /* Pods */ = {
isa = PBXGroup;
children = (
);
name = Pods;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
2D5378251FAA1A9400D5DBA9 /* flutter_assets */,
3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
647DC95AB5350DB6D2264FFE /* Pods */,
50BAF1DF19E018DDF2B149B9 /* Frameworks */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
97C146F11CF9000F007C117D /* Supporting Files */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "<group>";
};
97C146F11CF9000F007C117D /* Supporting Files */ = {
isa = PBXGroup;
children = (
);
name = "Supporting Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
3F62E6580DEAFBE72C090A85 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
903A9F2558754FA70D0A7EA8 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0910;
ORGANIZATIONNAME = "The Chromium Authors";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 0910;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
};
3F62E6580DEAFBE72C090A85 /* [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;
};
903A9F2558754FA70D0A7EA8 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${PODS_ROOT}/../.symlinks/flutter/ios-release/Flutter.framework",
"${BUILT_PRODUCTS_DIR}/flutter_inappbrowser/flutter_inappbrowser.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_inappbrowser.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_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_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_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_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_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_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
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 = com.pichillilorenzo.flutter_inappbrowserExample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SWIFT3_OBJC_INFERENCE = On;
SWIFT_VERSION = 4.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
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 = com.pichillilorenzo.flutter_inappbrowserExample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_SWIFT3_OBJC_INFERENCE = On;
SWIFT_VERSION = 4.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0910"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
{
"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"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
<?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>flutter_inappbrowser_example</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>
#import "GeneratedPluginRegistrant.h"
\ No newline at end of file
import 'package:flutter/material.dart';
import 'package:flutter_inappbrowser/flutter_inappbrowser.dart';
class MyInAppBrowser extends InAppBrowser {
@override
void onLoadStart(String url) {
super.onLoadStart(url);
print("\n\nStarted $url\n\n");
}
@override
void onLoadStop(String url) {
super.onLoadStop(url);
print("\n\nStopped $url\n\n");
this.injectScriptFile("https://code.jquery.com/jquery-3.3.1.min.js");
/*this.injectScriptCode("""
\$( "body" ).html( "Next Step..." )
""");*/
this.injectStyleCode("""
body {
background-color: #3c3c3c !important;
}
""");
this.injectStyleFile("https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css");
}
@override
void onLoadError(String url, String code, String message) {
super.onLoadStop(url);
print("\n\nCan't load $url.. Error: $message\n\n");
}
@override
void onExit() {
super.onExit();
print("\n\nBrowser closed!\n\n");
}
}
MyInAppBrowser inAppBrowser = new MyInAppBrowser();
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: const Text('Plugin example app'),
),
body: new Center(
child: new RaisedButton(onPressed: () {
inAppBrowser.open("https://flutter.io/");
},
child: Text("Open InAppBrowser")
),
),
),
);
}
}
name: flutter_inappbrowser_example
description: Demonstrates how to use the flutter_inappbrowser plugin.
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# Read more about versioning at semver.org.
version: 1.0.0+1
environment:
sdk: ">=2.0.0-dev.68.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2
dev_dependencies:
flutter_test:
sdk: flutter
flutter_inappbrowser:
path: ../
# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.io/assets-and-images/#resolution-aware.
# For details regarding adding assets from package dependencies, see
# https://flutter.io/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.io/custom-fonts/#from-packages
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/lib" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/.idea" />
<excludeFolder url="file://$MODULE_DIR$/.pub" />
<excludeFolder url="file://$MODULE_DIR$/build" />
<excludeFolder url="file://$MODULE_DIR$/example/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/example/.pub" />
<excludeFolder url="file://$MODULE_DIR$/example/build" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/Flutter/flutter_assets/packages" />
</content>
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Dart SDK" level="project" />
<orderEntry type="library" name="Flutter Plugins" level="project" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android" name="Android">
<configuration>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="GEN_FOLDER_RELATIVE_PATH_APT" value="/android/gen" />
<option name="GEN_FOLDER_RELATIVE_PATH_AIDL" value="/android/gen" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/android/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/android/res" />
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/android/assets" />
<option name="LIBS_FOLDER_RELATIVE_PATH" value="/android/libs" />
<option name="PROGUARD_LOGS_FOLDER_RELATIVE_PATH" value="/android/proguard_logs" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$/android">
<sourceFolder url="file://$MODULE_DIR$/android/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/android/gen" isTestSource="false" generated="true" />
</content>
<content url="file://$MODULE_DIR$/example/android">
<sourceFolder url="file://$MODULE_DIR$/example/android/app/src/main/java" isTestSource="false" />
</content>
<orderEntry type="jdk" jdkName="Android API 25 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Flutter for Android" level="project" />
</component>
</module>
.idea/
.vagrant/
.sconsign.dblite
.svn/
.DS_Store
*.swp
profile
DerivedData/
build/
GeneratedPluginRegistrant.h
GeneratedPluginRegistrant.m
.generated/
*.pbxuser
*.mode1v3
*.mode2v3
*.perspectivev3
!default.pbxuser
!default.mode1v3
!default.mode2v3
!default.perspectivev3
xcuserdata
*.moved-aside
*.pyc
*sync/
Icon?
.tags*
/Flutter/Generated.xcconfig
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import <Flutter/Flutter.h>
@interface InAppBrowser : NSObject<FlutterPlugin>
+ (void)registerWithRegistrar:(nonnull NSObject<FlutterPluginRegistrar> *)registrar;
@end
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import "InAppBrowser.h"
#import <flutter_inappbrowser/flutter_inappbrowser-Swift.h>
@implementation InAppBrowser : NSObject
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
[SwiftFlutterPlugin registerWithRegistrar:registrar];
}
@end
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
import Flutter
import UIKit
import WebKit
import Foundation
import AVFoundation
let kInAppBrowserTargetSelf = "_self"
let kInAppBrowserTargetSystem = "_system"
let kInAppBrowserTargetBlank = "_blank"
let kInAppBrowserToolbarBarPositionBottom = "bottom"
let kInAppBrowserToolbarBarPositionTop = "top"
let TOOLBAR_HEIGHT: Float = 44.0
let STATUSBAR_HEIGHT: Float = 20.0
let LOCATIONBAR_HEIGHT: Float = 21.0
let FOOTER_HEIGHT: Float = (TOOLBAR_HEIGHT + LOCATIONBAR_HEIGHT)
@objcMembers
class CDVInAppBrowserOptions: NSObject {
var location = false
var toolbar = false
var closebuttoncaption = ""
var closebuttoncolor = ""
var toolbarposition = ""
var toolbarcolor = ""
var toolbartranslucent = false
var hidenavigationbuttons = false
var navigationbuttoncolor = ""
var clearcache = false
var clearsessioncache = false
var hidespinner = false
var presentationstyle = ""
var transitionstyle = ""
var enableviewportscale = false
var mediaplaybackrequiresuseraction = false
var allowinlinemediaplayback = false
var keyboarddisplayrequiresuseraction = false
var suppressesincrementalrendering = false
var hidden = false
var disallowoverscroll = false
override init() {
super.init()
// default values
location = true
toolbar = true
closebuttoncaption = "Done"
closebuttoncolor = "#FFFFFF"
toolbarposition = kInAppBrowserToolbarBarPositionBottom
clearcache = false
clearsessioncache = false
hidespinner = false
enableviewportscale = false
mediaplaybackrequiresuseraction = false
allowinlinemediaplayback = false
keyboarddisplayrequiresuseraction = true
suppressesincrementalrendering = false
hidden = false
disallowoverscroll = false
hidenavigationbuttons = false
toolbarcolor = ""
toolbartranslucent = true
}
class func parseOptions(_ options: String) -> CDVInAppBrowserOptions {
let obj = CDVInAppBrowserOptions()
// NOTE: this parsing does not handle quotes within values
let pairs = options.components(separatedBy: ",")
// parse keys and values, set the properties
for pair: String in pairs {
let keyvalue = pair.components(separatedBy: "=")
if keyvalue.count == 2 {
let key: String = keyvalue[0].lowercased()
let value: String = keyvalue[1]
let value_lc: String = value.lowercased()
let isBoolean: Bool = (value_lc == "yes") || (value_lc == "no")
let numberFormatter = NumberFormatter()
numberFormatter.allowsFloats = true
let isNumber: Bool = numberFormatter.number(from: value_lc) != nil
// set the property according to the key name
if obj.responds(to: NSSelectorFromString(key)) {
if isNumber {
obj.setValue(numberFormatter.number(from: value_lc), forKey: key)
}
else if isBoolean {
obj.setValue(((value_lc == "yes") ? 1 : 0), forKey: key)
}
else {
obj.setValue(value, forKey: key)
}
}
}
}
return obj
}
}
public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
var inAppBrowserViewController: CDVInAppBrowserViewController?
var tmpWindow: UIWindow?
var channel: FlutterMethodChannel
private var previousStatusBarStyle = -1
public init(with registrar: FlutterPluginRegistrar) {
channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappbrowser", binaryMessenger: registrar.messenger())
}
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappbrowser", binaryMessenger: registrar.messenger())
let instance = SwiftFlutterPlugin(with: registrar)
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let arguments = call.arguments as? NSDictionary
switch call.method {
case "open":
self.open(arguments: arguments!, result: result)
break
case "close":
self.close()
result(true)
break
case "show":
self.show()
result(true)
break
case "hide":
self.hide()
result(true)
break
case "injectScriptCode":
self.injectScriptCode(arguments: arguments!)
result(true)
break
case "injectScriptFile":
self.injectScriptFile(arguments: arguments!)
result(true)
break
case "injectStyleCode":
self.injectStyleCode(arguments: arguments!)
result(true)
break
case "injectStyleFile":
self.injectStyleFile(arguments: arguments!)
result(true)
break
default:
break
}
}
func setting(forKey key: String) -> Any {
return ""//commandDelegate.settings[key.lowercased()]!
}
func onReset() {
close()
}
func close() {
if inAppBrowserViewController == nil {
print("IAB.close() called but it was already closed.")
return
}
// Things are cleaned up in browserExit.
inAppBrowserViewController?.close()
}
func isSystemUrl(_ url: URL) -> Bool {
if (url.host == "itunes.apple.com") {
return true
}
return false
}
public func open(arguments: NSDictionary, result: @escaping FlutterResult) {
let url: String? = (arguments["url"] as? String)!
var target: String? = (arguments["target"] as? String)!
target = target != nil ? target : kInAppBrowserTargetSelf
let options = (arguments["options"] as? String)!
if url != nil {
let baseUrl: URL? = nil
let absoluteUrl = URL(string: url!, relativeTo: baseUrl)?.absoluteURL
if isSystemUrl(absoluteUrl!) {
target = kInAppBrowserTargetSystem
}
if (target == kInAppBrowserTargetSelf) {
open(inCordovaWebView: absoluteUrl!, withOptions: options)
}
else if (target == kInAppBrowserTargetSystem) {
open(inSystem: absoluteUrl!)
}
else {
// _blank or anything else
openIn(inAppBrowser: absoluteUrl!, withOptions: options)
}
}
else {
result(false)
}
result(true)
}
func openIn(inAppBrowser url: URL, withOptions options: String) {
let browserOptions = CDVInAppBrowserOptions.parseOptions(options)
if browserOptions.clearcache {
let _: HTTPCookie?
let storage = HTTPCookieStorage.shared
for cookie in storage.cookies! {
if !(cookie.domain.isEqual(".^filecookies^") ) {
storage.deleteCookie(cookie)
}
}
}
if browserOptions.clearsessioncache {
let _: HTTPCookie?
let storage = HTTPCookieStorage.shared
for cookie in storage.cookies! {
if !(cookie.domain.isEqual(".^filecookies^") && cookie.isSessionOnly) {
storage.deleteCookie(cookie)
}
}
}
if inAppBrowserViewController == nil {
var userAgent: String = UIWebView().stringByEvaluatingJavaScript(from: "navigator.userAgent")!
let overrideUserAgent: String = ""
let appendUserAgent: String = ""
if overrideUserAgent != "" {
userAgent = overrideUserAgent
}
if appendUserAgent != "" {
userAgent = userAgent + (appendUserAgent)
}
if !(self.tmpWindow != nil) {
let frame: CGRect = UIScreen.main.bounds
self.tmpWindow = UIWindow(frame: frame)
}
inAppBrowserViewController = CDVInAppBrowserViewController(userAgent: userAgent, prevUserAgent: userAgent, browserOptions: browserOptions, tmpWindow: tmpWindow)
inAppBrowserViewController?.navigationDelegate = self
}
inAppBrowserViewController?.showLocationBar(browserOptions.location)
inAppBrowserViewController?.showToolBar(browserOptions.toolbar, toolbarPosition: browserOptions.toolbarposition)
if browserOptions.closebuttoncaption != nil || browserOptions.closebuttoncolor != nil {
inAppBrowserViewController?.setCloseButtonTitle(browserOptions.closebuttoncaption, colorString: browserOptions.closebuttoncolor)
}
// Set Presentation Style
var presentationStyle: UIModalPresentationStyle = .fullScreen
// default
if browserOptions.presentationstyle != nil {
if (browserOptions.presentationstyle.lowercased() == "pagesheet") {
presentationStyle = .pageSheet
}
else if (browserOptions.presentationstyle.lowercased() == "formsheet") {
presentationStyle = .formSheet
}
}
inAppBrowserViewController?.modalPresentationStyle = presentationStyle
// Set Transition Style
var transitionStyle: UIModalTransitionStyle = .coverVertical
// default
if browserOptions.transitionstyle != nil {
if (browserOptions.transitionstyle.lowercased() == "fliphorizontal") {
transitionStyle = .flipHorizontal
}
else if (browserOptions.transitionstyle.lowercased() == "crossdissolve") {
transitionStyle = .crossDissolve
}
}
inAppBrowserViewController?.modalTransitionStyle = transitionStyle
// prevent webView from bouncing
if browserOptions.disallowoverscroll {
if inAppBrowserViewController?.webView?.responds(to: #selector(getter: inAppBrowserViewController?.webView?.scrollView)) ?? false {
(inAppBrowserViewController?.webView?.scrollView)?.bounces = false
}
else {
for subview: UIView in (inAppBrowserViewController?.webView?.subviews)! {
if subview is UIScrollView {
(subview as? UIScrollView)?.bounces = false
}
}
}
}
// UIWebView options
inAppBrowserViewController?.webView?.scalesPageToFit = browserOptions.enableviewportscale
inAppBrowserViewController?.webView?.mediaPlaybackRequiresUserAction = browserOptions.mediaplaybackrequiresuseraction
inAppBrowserViewController?.webView?.allowsInlineMediaPlayback = browserOptions.allowinlinemediaplayback
//if IsAtLeastiOSVersion("6.0") {
inAppBrowserViewController?.webView?.keyboardDisplayRequiresUserAction = browserOptions.keyboarddisplayrequiresuseraction
inAppBrowserViewController?.webView?.suppressesIncrementalRendering = browserOptions.suppressesincrementalrendering
//}
inAppBrowserViewController?.navigate(to: url)
if !browserOptions.hidden {
show()
}
}
public func show() {
if inAppBrowserViewController == nil {
print("Tried to show IAB after it was closed.")
return
}
if previousStatusBarStyle != -1 {
print("Tried to show IAB while already shown")
return
}
previousStatusBarStyle = UIApplication.shared.statusBarStyle.rawValue
let nav = CDVInAppBrowserNavigationController(rootViewController: inAppBrowserViewController!)
nav.orientationDelegate = inAppBrowserViewController
nav.isNavigationBarHidden = true
nav.modalPresentationStyle = (inAppBrowserViewController?.modalPresentationStyle)!
weak var weakSelf: SwiftFlutterPlugin? = self
// Run later to avoid the "took a long time" log message.
DispatchQueue.main.async(execute: {() -> Void in
if weakSelf?.inAppBrowserViewController != nil {
if !(self.tmpWindow != nil) {
let frame: CGRect = UIScreen.main.bounds
self.tmpWindow = UIWindow(frame: frame)
}
let tmpController = UIViewController()
let baseWindowLevel = UIApplication.shared.keyWindow?.windowLevel
self.tmpWindow?.rootViewController = tmpController
self.tmpWindow?.windowLevel = UIWindowLevel(baseWindowLevel! + 1)
self.tmpWindow?.makeKeyAndVisible()
tmpController.present(nav, animated: true) { () -> Void in }
}
})
}
public func hide() {
if inAppBrowserViewController == nil {
print("Tried to hide IAB after it was closed.")
return
}
if previousStatusBarStyle == -1 {
print("Tried to hide IAB while already hidden")
return
}
previousStatusBarStyle = UIApplication.shared.statusBarStyle.rawValue
// Run later to avoid the "took a long time" log message.
DispatchQueue.main.async(execute: {() -> Void in
if self.inAppBrowserViewController != nil {
self.previousStatusBarStyle = -1
self.inAppBrowserViewController?.presentingViewController?.dismiss(animated: true, completion: {() -> Void in
self.tmpWindow?.windowLevel = 0.0
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
})
}
})
}
func open(inCordovaWebView url: URL, withOptions options: String) {
_ = URLRequest(url: url)
openIn(inAppBrowser: url, withOptions: options)
}
func open(inSystem url: URL) {
if UIApplication.shared.openURL(url) == false {
NotificationCenter.default.post(Notification(name: Notification.Name(rawValue: "CDVPluginHandleOpenURLNotification"), object: url))
}
}
// This is a helper method for the inject{Script|Style}{Code|File} API calls, which
// provides a consistent method for injecting JavaScript code into the document.
//
// If a wrapper string is supplied, then the source string will be JSON-encoded (adding
// quotes) and wrapped using string formatting. (The wrapper string should have a single
// '%@' marker).
//
// If no wrapper is supplied, then the source string is executed directly.
func injectDeferredObject(_ source: String, withWrapper jsWrapper: String) {
if jsWrapper != nil {
let jsonData: Data? = try? JSONSerialization.data(withJSONObject: [source], options: [])
let sourceArrayString = String(data: jsonData!, encoding: String.Encoding.utf8)
if sourceArrayString != nil {
let sourceString: String? = (sourceArrayString! as NSString).substring(with: NSRange(location: 1, length: (sourceArrayString?.characters.count ?? 0) - 2))
let jsToInject = String(format: jsWrapper, sourceString!)
inAppBrowserViewController?.webView?.stringByEvaluatingJavaScript(from: jsToInject)
}
}
else {
inAppBrowserViewController?.webView?.stringByEvaluatingJavaScript(from: source)
}
}
public func injectScriptCode(arguments: NSDictionary) {
let jsWrapper = "(function(){JSON.stringify([eval(%@)])})()"
injectDeferredObject(arguments["source"] as! String, withWrapper: jsWrapper)
}
public func injectScriptFile(arguments: NSDictionary) {
let jsWrapper = "(function(d) { var c = d.createElement('script'); c.src = %@; d.body.appendChild(c); })(document)"
injectDeferredObject(arguments["urlFile"] as! String, withWrapper: jsWrapper)
}
public func injectStyleCode(arguments: NSDictionary) {
let jsWrapper = "(function(d) { var c = d.createElement('style'); c.innerHTML = %@; d.body.appendChild(c); })(document)"
injectDeferredObject(arguments["source"] as! String, withWrapper: jsWrapper)
}
public func injectStyleFile(arguments: NSDictionary) {
let jsWrapper = "(function(d) { var c = d.createElement('link'); c.rel='stylesheet', c.type='text/css'; c.href = %@; d.body.appendChild(c); })(document)"
injectDeferredObject(arguments["urlFile"] as! String, withWrapper: jsWrapper)
}
func webViewDidStartLoad(_ webView: UIWebView) {
let url: String = inAppBrowserViewController!.currentURL!.absoluteString
channel.invokeMethod("loadstart", arguments: ["type": "loadstart", "url": url])
}
func webViewDidFinishLoad(_ webView: UIWebView) {
let url: String = inAppBrowserViewController!.currentURL!.absoluteString
channel.invokeMethod("loadstop", arguments: ["type": "loadstop", "url": url])
}
func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
let url: String = inAppBrowserViewController!.currentURL!.absoluteString
let arguments = ["type": "loaderror", "url": url, "code": error._code, "message": error.localizedDescription] as [String : Any]
channel.invokeMethod("loaderror", arguments: arguments)
}
func browserExit() {
channel.invokeMethod("exit", arguments: ["type": "exit"])
// Set navigationDelegate to nil to ensure no callbacks are received from it.
inAppBrowserViewController?.navigationDelegate = nil
// Don't recycle the ViewController since it may be consuming a lot of memory.
// Also - this is required for the PDF/User-Agent bug work-around.
inAppBrowserViewController = nil
//if (IsAtLeastiOSVersion(@"7.0")) {
if previousStatusBarStyle != -1 {
UIApplication.shared.statusBarStyle = UIStatusBarStyle(rawValue: previousStatusBarStyle)!
}
//}
previousStatusBarStyle = -1
// this value was reset before reapplying it. caused statusbar to stay black on ios7
}
}
class CDVInAppBrowserViewController: UIViewController, UIWebViewDelegate {
@IBOutlet var webView: UIWebView!
@IBOutlet var closeButton: UIBarButtonItem!
@IBOutlet var addressLabel: UILabel!
@IBOutlet var backButton: UIBarButtonItem!
@IBOutlet var forwardButton: UIBarButtonItem!
@IBOutlet var spinner: UIActivityIndicatorView!
@IBOutlet var toolbar: UIToolbar!
weak var orientationDelegate: CDVInAppBrowserViewController?
weak var navigationDelegate: SwiftFlutterPlugin?
var currentURL: URL?
var tmpWindow: UIWindow?
private var userAgent = ""
private var prevUserAgent = ""
private var userAgentLockToken: Int = 0
private var browserOptions: CDVInAppBrowserOptions?
init(userAgent: String, prevUserAgent: String, browserOptions: CDVInAppBrowserOptions, tmpWindow: UIWindow?) {
super.init(nibName: nil, bundle: nil)
self.userAgent = userAgent
self.prevUserAgent = prevUserAgent
self.browserOptions = browserOptions
self.tmpWindow = tmpWindow
createViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// Prevent crashes on closing windows
deinit {
webView?.delegate = nil
}
func createViews() {
// We create the views in code for primarily for ease of upgrades and not requiring an external .xib to be included
var webViewBounds: CGRect = view.bounds
let toolbarIsAtBottom: Bool = !(browserOptions!.toolbarposition == kInAppBrowserToolbarBarPositionTop)
webViewBounds.size.height -= CGFloat((browserOptions?.location)! ? FOOTER_HEIGHT : TOOLBAR_HEIGHT)
webView = UIWebView(frame: webViewBounds)// as WKWebView
webView?.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(webView!)
view.sendSubview(toBack: webView!)
webView?.delegate = self
webView?.backgroundColor = UIColor.white
webView?.clearsContextBeforeDrawing = true
webView?.clipsToBounds = true
webView?.contentMode = .scaleToFill
webView?.isMultipleTouchEnabled = true
webView?.isOpaque = true
webView?.scalesPageToFit = false
webView?.isUserInteractionEnabled = true
spinner = UIActivityIndicatorView(activityIndicatorStyle: .gray)
spinner.alpha = 1.000
spinner.autoresizesSubviews = true
spinner.autoresizingMask = [.flexibleLeftMargin, .flexibleTopMargin, .flexibleBottomMargin, .flexibleRightMargin]
spinner.clearsContextBeforeDrawing = false
spinner.clipsToBounds = false
spinner.contentMode = .scaleToFill
spinner.frame = CGRect(x: (webView?.frame.midX)!, y: (webView?.frame.midY)!, width: 20.0, height: 20.0)
spinner.isHidden = false
spinner.hidesWhenStopped = true
spinner.isMultipleTouchEnabled = false
spinner.isOpaque = false
spinner.isUserInteractionEnabled = false
spinner.stopAnimating()
closeButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.close))
closeButton.isEnabled = true
let flexibleSpaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let fixedSpaceButton = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
fixedSpaceButton.width = 20
let toolbarY: Float = toolbarIsAtBottom ? Float(view.bounds.size.height) - TOOLBAR_HEIGHT : 0.0
let toolbarFrame = CGRect(x: 0.0, y: CGFloat(toolbarY), width: view.bounds.size.width, height: CGFloat(TOOLBAR_HEIGHT))
toolbar = UIToolbar(frame: toolbarFrame)
toolbar.alpha = 1.000
toolbar.autoresizesSubviews = true
toolbar.autoresizingMask = toolbarIsAtBottom ? ([.flexibleWidth, .flexibleTopMargin]) : .flexibleWidth
toolbar.barStyle = .blackOpaque
toolbar.clearsContextBeforeDrawing = false
toolbar.clipsToBounds = false
toolbar.contentMode = .scaleToFill
toolbar.isHidden = false
toolbar.isMultipleTouchEnabled = false
toolbar.isOpaque = false
toolbar.isUserInteractionEnabled = true
if browserOptions?.toolbarcolor != nil {
// Set toolbar color if user sets it in options
toolbar.barTintColor = color(fromHexString: (browserOptions?.toolbarcolor)!)
}
if !(browserOptions?.toolbartranslucent)! {
// Set toolbar translucent to no if user sets it in options
toolbar.isTranslucent = false
}
let labelInset: CGFloat = 5.0
let locationBarY: Float = toolbarIsAtBottom ? Float(view.bounds.size.height) - FOOTER_HEIGHT : Float(view.bounds.size.height) - LOCATIONBAR_HEIGHT
addressLabel = UILabel(frame: CGRect(x: labelInset, y: CGFloat(locationBarY), width: view.bounds.size.width - labelInset, height: CGFloat(LOCATIONBAR_HEIGHT)))
addressLabel.adjustsFontSizeToFitWidth = false
addressLabel.alpha = 1.000
addressLabel.autoresizesSubviews = true
addressLabel.autoresizingMask = [.flexibleWidth, .flexibleRightMargin, .flexibleTopMargin]
addressLabel.backgroundColor = UIColor.clear// as? CGColor
addressLabel.baselineAdjustment = .alignCenters
addressLabel.clearsContextBeforeDrawing = true
addressLabel.clipsToBounds = true
addressLabel.contentMode = .scaleToFill
addressLabel.isEnabled = true
addressLabel.isHidden = false
addressLabel.lineBreakMode = .byTruncatingTail
if addressLabel.responds(to: NSSelectorFromString("setMinimumScaleFactor:")) {
addressLabel.setValue((10.0 / UIFont.labelFontSize), forKey: "minimumScaleFactor")
}
else if addressLabel.responds(to: NSSelectorFromString("setMinimumFontSize:")) {
addressLabel.setValue(10.0, forKey: "minimumFontSize")
}
addressLabel.isMultipleTouchEnabled = false
addressLabel.numberOfLines = 1
addressLabel.isOpaque = false
addressLabel.shadowOffset = CGSize(width: 0.0, height: -1.0)
addressLabel.text = NSLocalizedString("Loading...", comment: "")
addressLabel.textAlignment = .left
addressLabel.textColor = UIColor(white: 1.000, alpha: 1.000)
addressLabel.isUserInteractionEnabled = false
let frontArrowString = NSLocalizedString("►", comment: "")
// create arrow from Unicode char
forwardButton = UIBarButtonItem(title: frontArrowString, style: .plain, target: self, action: #selector(self.goForward))
forwardButton.isEnabled = true
forwardButton.imageInsets = UIEdgeInsets.zero as? UIEdgeInsets ?? UIEdgeInsets()
if browserOptions?.navigationbuttoncolor != nil {
// Set button color if user sets it in options
forwardButton.tintColor = color(fromHexString: (browserOptions?.navigationbuttoncolor)!)
}
let backArrowString = NSLocalizedString("◄", comment: "")
// create arrow from Unicode char
backButton = UIBarButtonItem(title: backArrowString, style: .plain, target: self, action: #selector(self.goBack))
backButton.isEnabled = true
backButton.imageInsets = UIEdgeInsets.zero as? UIEdgeInsets ?? UIEdgeInsets()
if browserOptions?.navigationbuttoncolor != nil {
// Set button color if user sets it in options
backButton.tintColor = color(fromHexString: (browserOptions?.navigationbuttoncolor)!)
}
// Filter out Navigation Buttons if user requests so
if (browserOptions?.hidenavigationbuttons)! {
toolbar.items = [closeButton, flexibleSpaceButton]
}
else {
toolbar.items = [closeButton, flexibleSpaceButton, backButton, fixedSpaceButton, forwardButton]
}
view.backgroundColor = UIColor.gray// as? CGColor
view.addSubview(toolbar)
view.addSubview(addressLabel)
view.addSubview(spinner)
}
func setWebViewFrame(_ frame: CGRect) {
print("Setting the WebView's frame to \(NSStringFromCGRect(frame))")
webView?.frame = frame
}
func setCloseButtonTitle(_ title: String, colorString: String) {
// the advantage of using UIBarButtonSystemItemDone is the system will localize it for you automatically
// but, if you want to set this yourself, knock yourself out (we can't set the title for a system Done button, so we have to create a new one)
closeButton = nil
// Initialize with title if title is set, otherwise the title will be 'Done' localized
closeButton = title != nil ? UIBarButtonItem(title: title, style: .bordered, target: self, action: #selector(self.close)) : UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.close))
closeButton.isEnabled = true
// If color on closebutton is requested then initialize with that that color, otherwise use initialize with default
closeButton.tintColor = colorString != nil ? color(fromHexString: colorString) : UIColor(red: 60.0 / 255.0, green: 136.0 / 255.0, blue: 230.0 / 255.0, alpha: 1)
var items = toolbar.items
items![0] = closeButton
toolbar.items = items //as? [AVMetadataItem] ?? [AVMetadataItem]()
}
func showLocationBar(_ show: Bool) {
var locationbarFrame: CGRect = addressLabel.frame
let toolbarVisible: Bool = !toolbar.isHidden
// prevent double show/hide
if show == !addressLabel.isHidden {
return
}
if show {
addressLabel.isHidden = false
if toolbarVisible {
// toolBar at the bottom, leave as is
// put locationBar on top of the toolBar
var webViewBounds: CGRect = view.bounds
webViewBounds.size.height -= CGFloat(FOOTER_HEIGHT)
setWebViewFrame(webViewBounds)
locationbarFrame.origin.y = webViewBounds.size.height
addressLabel.frame = locationbarFrame
}
else {
// no toolBar, so put locationBar at the bottom
var webViewBounds: CGRect = view.bounds
webViewBounds.size.height -= CGFloat(LOCATIONBAR_HEIGHT)
setWebViewFrame(webViewBounds)
locationbarFrame.origin.y = webViewBounds.size.height
addressLabel.frame = locationbarFrame
}
}
else {
addressLabel.isHidden = true
if toolbarVisible {
// locationBar is on top of toolBar, hide locationBar
// webView take up whole height less toolBar height
var webViewBounds: CGRect = view.bounds
webViewBounds.size.height -= CGFloat(TOOLBAR_HEIGHT)
setWebViewFrame(webViewBounds)
}
else {
// no toolBar, expand webView to screen dimensions
setWebViewFrame(view.bounds)
}
}
}
func showToolBar(_ show: Bool, toolbarPosition: String) {
var toolbarFrame: CGRect = toolbar.frame
var locationbarFrame: CGRect = addressLabel.frame
let locationbarVisible: Bool = !addressLabel.isHidden
// prevent double show/hide
if show == !toolbar.isHidden {
return
}
if show {
toolbar.isHidden = false
var webViewBounds: CGRect = view.bounds
if locationbarVisible {
// locationBar at the bottom, move locationBar up
// put toolBar at the bottom
webViewBounds.size.height -= CGFloat(FOOTER_HEIGHT)
locationbarFrame.origin.y = webViewBounds.size.height
addressLabel.frame = locationbarFrame
toolbar.frame = toolbarFrame
}
else {
// no locationBar, so put toolBar at the bottom
var webViewBounds: CGRect = view.bounds
webViewBounds.size.height -= CGFloat(TOOLBAR_HEIGHT)
toolbar.frame = toolbarFrame
}
if (toolbarPosition == kInAppBrowserToolbarBarPositionTop) {
toolbarFrame.origin.y = 0
webViewBounds.origin.y += toolbarFrame.size.height
setWebViewFrame(webViewBounds)
}
else {
toolbarFrame.origin.y = webViewBounds.size.height + CGFloat(LOCATIONBAR_HEIGHT)
}
setWebViewFrame(webViewBounds)
}
else {
toolbar.isHidden = true
if locationbarVisible {
// locationBar is on top of toolBar, hide toolBar
// put locationBar at the bottom
// webView take up whole height less locationBar height
var webViewBounds: CGRect = view.bounds
webViewBounds.size.height -= CGFloat(LOCATIONBAR_HEIGHT)
setWebViewFrame(webViewBounds)
// move locationBar down
locationbarFrame.origin.y = webViewBounds.size.height
addressLabel.frame = locationbarFrame
}
else {
// no locationBar, expand webView to screen dimensions
setWebViewFrame(view.bounds)
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
// override func viewDidUnload() {
// webView?.loadHTMLString(nil, baseURL: nil)
// CDVUserAgentUtil.releaseLock(userAgentLockToken)
// super.viewDidUnload()
// }
// func preferredStatusBarStyle() -> UIStatusBarStyle {
// return .default
// }
//
// func prefersStatusBarHidden() -> Bool {
// return false
// }
@objc func close() {
currentURL = nil
if (navigationDelegate != nil) {
navigationDelegate?.browserExit()
}
// if (navigationDelegate != nil) && navigationDelegate?.responds(to: #selector(self.browserExit)) {
// navigationDelegate?.browserExit()
// }
weak var weakSelf = self// as? UIViewController
// Run later to avoid the "took a long time" log message.
DispatchQueue.main.async(execute: {() -> Void in
if (weakSelf?.responds(to: #selector(getter: self.presentingViewController)))! {
weakSelf?.presentingViewController?.dismiss(animated: true, completion: {() -> Void in
self.tmpWindow?.windowLevel = 0.0
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
})
}
else {
weakSelf?.parent?.dismiss(animated: true, completion: {() -> Void in
self.tmpWindow?.windowLevel = 0.0
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
})
}
})
}
func navigate(to url: URL) {
let request = URLRequest(url: url)
currentURL = url
webView?.loadRequest(request)
// if userAgentLockToken != 0 {
// webView?.load(request, mimeType: <#String#>, textEncodingName: <#String#>, baseURL: <#URL#>)
// }
// else {
// weak var weakSelf: CDVInAppBrowserViewController? = self
// CDVUserAgentUtil.acquireLock({(_ lockToken: Int) -> Void in
// userAgentLockToken = lockToken
// CDVUserAgentUtil.setUserAgent(userAgent, lockToken: lockToken)
// weakSelf?.webView?.load(request)
// })
// }
}
@objc func goBack(_ sender: Any) {
webView?.goBack()
}
@objc func goForward(_ sender: Any) {
webView?.goForward()
}
override func viewWillAppear(_ animated: Bool) {
//if IsAtLeastiOSVersion("7.0") {
UIApplication.shared.statusBarStyle = preferredStatusBarStyle
//}
rePositionViews()
super.viewWillAppear(animated)
}
//
// On iOS 7 the status bar is part of the view's dimensions, therefore it's height has to be taken into account.
// The height of it could be hardcoded as 20 pixels, but that would assume that the upcoming releases of iOS won't
// change that value.
//
func getStatusBarOffset() -> Float {
let statusBarFrame: CGRect = UIApplication.shared.statusBarFrame
let statusBarOffset: Float = Float(min(statusBarFrame.size.width, statusBarFrame.size.height))//IsAtLeastiOSVersion("7.0") ? min(statusBarFrame.size.width, statusBarFrame.size.height) : 0.0
return statusBarOffset
}
func rePositionViews() {
if (browserOptions?.toolbarposition == kInAppBrowserToolbarBarPositionTop) {
webView?.frame = CGRect(x: (webView?.frame.origin.x)!, y: CGFloat(TOOLBAR_HEIGHT), width: (webView?.frame.size.width)!, height: (webView?.frame.size.height)!)
toolbar.frame = CGRect(x: toolbar.frame.origin.x, y: CGFloat(getStatusBarOffset()), width: toolbar.frame.size.width, height: toolbar.frame.size.height)
}
}
// Helper function to convert hex color string to UIColor
// Assumes input like "#00FF00" (#RRGGBB).
// Taken from https://stackoverflow.com/questions/1560081/how-can-i-create-a-uicolor-from-a-hex-string
func color(fromHexString: String, alpha:CGFloat? = 1.0) -> UIColor {
// Convert hex string to an integer
let hexint = Int(self.intFromHexString(hexStr: fromHexString))
let red = CGFloat((hexint & 0xff0000) >> 16) / 255.0
let green = CGFloat((hexint & 0xff00) >> 8) / 255.0
let blue = CGFloat((hexint & 0xff) >> 0) / 255.0
let alpha = alpha!
// Create color object, specifying alpha as well
let color = UIColor(red: red, green: green, blue: blue, alpha: alpha)
return color
}
func intFromHexString(hexStr: String) -> UInt32 {
var hexInt: UInt32 = 0
// Create scanner
let scanner: Scanner = Scanner(string: hexStr)
// Tell scanner to skip the # character
scanner.charactersToBeSkipped = CharacterSet(charactersIn: "#")
// Scan hex value
scanner.scanHexInt32(&hexInt)
return hexInt
}
// MARK: UIWebViewDelegate
func webViewDidStartLoad(_ theWebView: UIWebView) {
// loading url, start spinner, update back/forward
addressLabel.text = NSLocalizedString("Loading...", comment: "")
backButton.isEnabled = theWebView.canGoBack
forwardButton.isEnabled = theWebView.canGoForward
print((browserOptions?.hidespinner)! ? "Yes" : "No")
if !(browserOptions?.hidespinner)! {
spinner.startAnimating()
}
return (navigationDelegate?.webViewDidStartLoad(theWebView))!
}
// func webView(_ theWebView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
// let isTopLevelNavigation: Bool? = request.url == request.mainDocumentURL
// if isTopLevelNavigation ?? false {
// currentURL = request.url
// }
//
// return (navigationDelegate?.webView(theWebView, shouldStartLoadWith: request, navigationType: navigationType))!
// }
func webViewDidFinishLoad(_ theWebView: UIWebView) {
// update url, stop spinner, update back/forward
currentURL = theWebView.request?.url
addressLabel.text = currentURL?.absoluteString
backButton.isEnabled = theWebView.canGoBack
forwardButton.isEnabled = theWebView.canGoForward
spinner.stopAnimating()
// Work around a bug where the first time a PDF is opened, all UIWebViews
// reload their User-Agent from NSUserDefaults.
// This work-around makes the following assumptions:
// 1. The app has only a single Cordova Webview. If not, then the app should
// take it upon themselves to load a PDF in the background as a part of
// their start-up flow.
// 2. That the PDF does not require any additional network requests. We change
// the user-agent here back to that of the CDVViewController, so requests
// from it must pass through its white-list. This *does* break PDFs that
// contain links to other remote PDF/websites.
// More info at https://issues.apache.org/jira/browse/CB-2225
let isPDF: Bool = "true" == theWebView.stringByEvaluatingJavaScript(from: "document.body==null")
if isPDF {
//CDVUserAgentUtil.setUserAgent(prevUserAgent, lockToken: userAgentLockToken)
}
navigationDelegate?.webViewDidFinishLoad(theWebView)
}
func webView(_ theWebView: UIWebView, didFailLoadWithError error: Error) {
// log fail message, stop spinner, update back/forward
print("webView:didFailLoadWithError - \(Int(error._code)): \(error.localizedDescription)")
backButton.isEnabled = theWebView.canGoBack
forwardButton.isEnabled = theWebView.canGoForward
spinner.stopAnimating()
addressLabel.text = NSLocalizedString("Load Error", comment: "")
navigationDelegate?.webView(theWebView, didFailLoadWithError: error)
}
// MARK: CDVScreenOrientationDelegate
// func shouldAutorotate() -> Bool {
// if (orientationDelegate != nil) && (orientationDelegate?.responds(to: #selector(getter: self.shouldAutorotate)))! {
// return orientationDelegate!.shouldAutorotate
// }
// return true
// }
//
// func supportedInterfaceOrientations() -> Int {
// if (orientationDelegate != nil) && (orientationDelegate?.responds(to: #selector(getter: self.supportedInterfaceOrientations)))! {
// return Int(orientationDelegate!.supportedInterfaceOrientations.rawValue)
// }
// //return Int(1 << .portrait)
// return 1
// }
// override func shouldAutorotate(to interfaceOrientation: UIInterfaceOrientation) -> Bool {
// if (orientationDelegate != nil) && (orientationDelegate?.responds(to: #selector(self.shouldAutorotateToInterfaceOrientation)))! {
// return orientationDelegate!.shouldAutorotate(to: interfaceOrientation)
// }
// return true
// }
}
class CDVInAppBrowserNavigationController: UINavigationController {
weak var orientationDelegate: AnyObject?
override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
if presentedViewController != nil {
super.dismiss(animated: flag, completion: completion)
}
}
override func viewDidLoad() {
var statusBarFrame: CGRect = invertFrameIfNeeded(UIApplication.shared.statusBarFrame)
statusBarFrame.size.height = CGFloat(STATUSBAR_HEIGHT)
// simplified from: http://stackoverflow.com/a/25669695/219684
let bgToolbar = UIToolbar(frame: statusBarFrame)
bgToolbar.barStyle = .default
bgToolbar.autoresizingMask = .flexibleWidth
view.addSubview(bgToolbar)
super.viewDidLoad()
}
func invertFrameIfNeeded(_ rect: CGRect) -> CGRect {
// We need to invert since on iOS 7 frames are always in Portrait context
// if !IsAtLeastiOSVersion("8.0") {
// if UIInterfaceOrientationIsLandscape(UIApplication.shared.statusBarOrientation) {
// let temp: CGFloat = rect.size.width
// rect.size.width = rect.size.height
// rect.size.height = temp
// }
// rect.origin = CGPoint.zero
// }
return rect
}
// MARK: CDVScreenOrientationDelegate
override var shouldAutorotate: Bool {
if (orientationDelegate != nil) && (orientationDelegate?.responds(to: #selector(getter: self.shouldAutorotate)))! {
return orientationDelegate!.shouldAutorotate
}
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if (orientationDelegate != nil) && (orientationDelegate?.responds(to: #selector(getter: self.supportedInterfaceOrientations)))! {
return orientationDelegate!.supportedInterfaceOrientations
}
//return Int(1 << .portrait)
return UIInterfaceOrientationMask(rawValue: 1)
}
// override func shouldAutorotate(to interfaceOrientation: UIInterfaceOrientation) -> Bool {
// if (orientationDelegate != nil) && (orientationDelegate?.responds(to: #selector(self.shouldAutorotateToInterfaceOrientation)))! {
// return orientationDelegate!.shouldAutorotate(to: interfaceOrientation)
// }
// return true
// }
}
#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
#
Pod::Spec.new do |s|
s.name = 'flutter_inappbrowser'
s.version = '0.0.1'
s.summary = 'A new Flutter plugin.'
s.description = <<-DESC
A new Flutter plugin.
DESC
s.homepage = 'http://example.com'
s.license = { :file => '../LICENSE' }
s.author = { 'Your Company' => 'email@example.com' }
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.public_header_files = 'Classes/**/*.h'
s.dependency 'Flutter'
s.ios.deployment_target = '8.0'
end
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
import 'dart:async';
import 'package:flutter/services.dart';
///Main class of the plugin.
class InAppBrowser {
static const MethodChannel _channel = const MethodChannel('com.pichillilorenzo/flutter_inappbrowser');
///
InAppBrowser () {
_channel.setMethodCallHandler(_handleMethod);
}
Future<dynamic> _handleMethod(MethodCall call) async {
switch(call.method) {
case "loadstart":
String url = call.arguments["url"];
onLoadStart(url);
break;
case "loadstop":
String url = call.arguments["url"];
onLoadStop(url);
break;
case "loaderror":
String url = call.arguments["url"];
String code = call.arguments["code"];
String message = call.arguments["message"];
onLoadError(url, code, message);
break;
case "exit":
onExit();
break;
case "customscheme":
String url = call.arguments["url"];
onCustomScheme(url);
break;
}
return new Future.value("");
}
///Opens an [url] in a new [InAppBrowser] instance or the system browser.
///
/// - [url]: The [url] to load __(String)__. Call [encodeUriComponent()] on this if the [url] contains Unicode characters.
///
/// - [target]: The target in which to load the [url], an optional parameter that defaults to `_self`. __(String)__
///
/// - `_self`: Opens in the [InAppBrowser].
/// - `_blank`: Opens in the [InAppBrowser].
/// - `_system`: Opens in the system's web browser.
///
/// - [options]: Options for the `InAppBrowser`. Optional, defaulting to: `location=yes`. _(String)_
///
/// The [options] string must not contain any blank space, and each feature's name/value pairs must be separated by a comma. Feature names are case insensitive.
///
/// All platforms support:
///
/// - __location__: Set to `yes` or `no` to turn the [InAppBrowser]'s location bar on or off.
///
/// **Android** supports these additional options:
///
/// - __hidden__: set to `yes` to create the browser and load the page, but not show it. The loadstop event fires when loading is complete. Omit or set to `no` (default) to have the browser open and load normally.
/// - __clearcache__: set to `yes` to have the browser's cookie cache cleared before the new window is opened
/// - __clearsessioncache__: set to `yes` to have the session cookie cache cleared before the new window is opened
/// - __closebuttoncaption__: set to a string to use as the close button's caption instead of a X. Note that you need to localize this value yourself.
/// - __closebuttoncolor__: set to a valid hex color string, for example: `#00ff00`, and it will change the
/// close button color from default, regardless of being a text or default X. Only has effect if user has location set to `yes`.
/// - __footer__: set to `yes` to show a close button in the footer similar to the iOS __Done__ button.
/// The close button will appear the same as for the header hence use __closebuttoncaption__ and __closebuttoncolor__ to set its properties.
/// - __footercolor__: set to a valid hex color string, for example `#00ff00` or `#CC00ff00` (`#aarrggbb`) , and it will change the footer color from default.
/// Only has effect if user has __footer__ set to `yes`.
/// - __hardwareback__: set to `yes` to use the hardware back button to navigate backwards through the `InAppBrowser`'s history. If there is no previous page, the `InAppBrowser` will close. The default value is `yes`, so you must set it to `no` if you want the back button to simply close the InAppBrowser.
/// - __hidenavigationbuttons__: set to `yes` to hide the navigation buttons on the location toolbar, only has effect if user has location set to `yes`. The default value is `no`.
/// - __hideurlbar__: set to `yes` to hide the url bar on the location toolbar, only has effect if user has location set to `yes`. The default value is `no`.
/// - __navigationbuttoncolor__: set to a valid hex color string, for example: `#00ff00`, and it will change the color of both navigation buttons from default. Only has effect if user has location set to `yes` and not hidenavigationbuttons set to `yes`.
/// - __toolbarcolor__: set to a valid hex color string, for example: `#00ff00`, and it will change the color the toolbar from default. Only has effect if user has location set to `yes`.
/// - __zoom__: set to `yes` to show Android browser's zoom controls, set to `no` to hide them. Default value is `yes`.
/// - __mediaPlaybackRequiresUserAction__: Set to `yes` to prevent HTML5 audio or video from autoplaying (defaults to `no`).
/// - __shouldPauseOnSuspend__: Set to `yes` to make InAppBrowser WebView to pause/resume with the app to stop background audio (this may be required to avoid Google Play issues like described in [CB-11013](https://issues.apache.org/jira/browse/CB-11013)).
/// - __useWideViewPort__: Sets whether the WebView should enable support for the "viewport" HTML meta tag or should use a wide viewport. When the value of the setting is `no`, the layout width is always set to the width of the WebView control in device-independent (CSS) pixels. When the value is `yes` and the page contains the viewport meta tag, the value of the width specified in the tag is used. If the page does not contain the tag or does not provide a width, then a wide viewport will be used. (defaults to `yes`).
///
/// **iOS** supports these additional options:
///
/// - __hidden__: set to `yes` to create the browser and load the page, but not show it. The loadstop event fires when loading is complete. Omit or set to `no` (default) to have the browser open and load normally.
/// - __clearcache__: set to `yes` to have the browser's cookie cache cleared before the new window is opened
/// - __clearsessioncache__: set to `yes` to have the session cookie cache cleared before the new window is opened
/// - __closebuttoncolor__: set as a valid hex color string, for example: `#00ff00`, to change from the default __Done__ button's color. Only applicable if toolbar is not disabled.
/// - __closebuttoncaption__: set to a string to use as the __Done__ button's caption. Note that you need to localize this value yourself.
/// - __disallowoverscroll__: Set to `yes` or `no` (default is `no`). Turns on/off the UIWebViewBounce property.
/// - __hidenavigationbuttons__: set to `yes` or `no` to turn the toolbar navigation buttons on or off (defaults to `no`). Only applicable if toolbar is not disabled.
/// - __navigationbuttoncolor__: set as a valid hex color string, for example: `#00ff00`, to change from the default color. Only applicable if navigation buttons are visible.
/// - __toolbar__: set to `yes` or `no` to turn the toolbar on or off for the InAppBrowser (defaults to `yes`)
/// - __toolbarcolor__: set as a valid hex color string, for example: `#00ff00`, to change from the default color of the toolbar. Only applicable if toolbar is not disabled.
/// - __toolbartranslucent__: set to `yes` or `no` to make the toolbar translucent(semi-transparent) (defaults to `yes`). Only applicable if toolbar is not disabled.
/// - __enableViewportScale__: Set to `yes` or `no` to prevent viewport scaling through a meta tag (defaults to `no`).
/// - __mediaPlaybackRequiresUserAction__: Set to `yes` to prevent HTML5 audio or video from autoplaying (defaults to `no`).
/// - __allowInlineMediaPlayback__: Set to `yes` or `no` to allow in-line HTML5 media playback, displaying within the browser window rather than a device-specific playback interface. The HTML's `video` element must also include the `webkit-playsinline` attribute (defaults to `no`)
/// - __keyboardDisplayRequiresUserAction__: Set to `yes` or `no` to open the keyboard when form elements receive focus via JavaScript's `focus()` call (defaults to `yes`).
/// - __suppressesIncrementalRendering__: Set to `yes` or `no` to wait until all new view content is received before being rendered (defaults to `no`).
/// - __presentationstyle__: Set to `pagesheet`, `formsheet` or `fullscreen` to set the [presentation style](http://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instp/UIViewController/modalPresentationStyle) (defaults to `fullscreen`).
/// - __transitionstyle__: Set to `fliphorizontal`, `crossdissolve` or `coververtical` to set the [transition style](http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instp/UIViewController/modalTransitionStyle) (defaults to `coververtical`).
/// - __toolbarposition__: Set to `top` or `bottom` (default is `bottom`). Causes the toolbar to be at the top or bottom of the window.
/// - __hidespinner__: Set to `yes` or `no` to change the visibility of the loading indicator (defaults to `no`).
Future<void> open(String url, {String target = "_self", String options = "location=yes"}) async {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('url', () => url);
args.putIfAbsent('target', () => target);
args.putIfAbsent('options', () => options);
return await _channel.invokeMethod('open', args);
}
///Displays an [InAppBrowser] window that was opened hidden. Calling this has no effect if the [InAppBrowser] was already visible.
Future<void> show() async {
return await _channel.invokeMethod('show');
}
///Hides the [InAppBrowser] window. Calling this has no effect if the [InAppBrowser] was already hidden.
Future<void> hide() async {
return await _channel.invokeMethod('hide');
}
///Closes the [InAppBrowser] window.
Future<void> close() async {
return await _channel.invokeMethod('close');
}
///Injects JavaScript code into the [InAppBrowser] window. (Only available when the target is set to `_blank` or to `_self`)
Future<void> injectScriptCode(String source) async {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('source', () => source);
return await _channel.invokeMethod('injectScriptCode', args);
}
///Injects a JavaScript file into the [InAppBrowser] window. (Only available when the target is set to `_blank` or to `_self`)
Future<void> injectScriptFile(String urlFile) async {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('urlFile', () => urlFile);
return await _channel.invokeMethod('injectScriptFile', args);
}
///Injects CSS into the [InAppBrowser] window. (Only available when the target is set to `_blank` or to `_self`)
Future<void> injectStyleCode(String source) async {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('source', () => source);
return await _channel.invokeMethod('injectStyleCode', args);
}
///Injects a CSS file into the [InAppBrowser] window. (Only available when the target is set to `_blank` or to `_self`)
Future<void> injectStyleFile(String urlFile) async {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('urlFile', () => urlFile);
return await _channel.invokeMethod('injectStyleFile', args);
}
///Event fires when the [InAppBrowser] starts to load an [url].
void onLoadStart(String url) {
}
///Event fires when the [InAppBrowser] finishes loading an [url].
void onLoadStop(String url) {
}
///Event fires when the [InAppBrowser] encounters an error loading an [url].
void onLoadError(String url, String code, String message) {
}
///Event fires when the [InAppBrowser] window is closed.
void onExit() {
}
///
void onCustomScheme(String url) {
}
}
name: flutter_inappbrowser
description: A Flutter plugin that allows you to open an in-app browser window. (porting of the popular cordova-plugin-inappbrowser).
version: 0.0.1
author: Lorenzo Pichilli <pichillilorenzo@gmail.com>
homepage: https://github.com/pichillilorenzo/flutter_inappbrowser
environment:
sdk: ">=2.0.0-dev.68.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
plugin:
androidPackage: com.pichillilorenzo.flutter_inappbrowser
pluginClass: InAppBrowser
# To add assets to your plugin package, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
#
# For details regarding assets in packages, see
# https://flutter.io/assets-and-images/#from-packages
#
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.io/assets-and-images/#resolution-aware.
# To add custom fonts to your plugin package, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts in packages, see
# https://flutter.io/custom-fonts/#from-packages
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment