Integration test for channel communication (#9621)
diff --git a/dev/devicelab/bin/tasks/platform_channel_test.dart b/dev/devicelab/bin/tasks/channels_integration_test.dart similarity index 77% copy from dev/devicelab/bin/tasks/platform_channel_test.dart copy to dev/devicelab/bin/tasks/channels_integration_test.dart index d1afc67..8b60289 100644 --- a/dev/devicelab/bin/tasks/platform_channel_test.dart +++ b/dev/devicelab/bin/tasks/channels_integration_test.dart
@@ -4,11 +4,11 @@ import 'dart:async'; -import 'package:flutter_devicelab/tasks/perf_tests.dart'; import 'package:flutter_devicelab/framework/adb.dart'; import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/integration_tests.dart'; Future<Null> main() async { deviceOperatingSystem = DeviceOperatingSystem.android; - await task(createPlatformServiceDriverTest()); + await task(createChannelsIntegrationTest()); }
diff --git a/dev/devicelab/bin/tasks/platform_channel_test_ios.dart b/dev/devicelab/bin/tasks/channels_integration_test_ios.dart similarity index 77% copy from dev/devicelab/bin/tasks/platform_channel_test_ios.dart copy to dev/devicelab/bin/tasks/channels_integration_test_ios.dart index 07760fb..9ac1a3a 100644 --- a/dev/devicelab/bin/tasks/platform_channel_test_ios.dart +++ b/dev/devicelab/bin/tasks/channels_integration_test_ios.dart
@@ -4,11 +4,11 @@ import 'dart:async'; -import 'package:flutter_devicelab/tasks/perf_tests.dart'; import 'package:flutter_devicelab/framework/adb.dart'; import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/integration_tests.dart'; Future<Null> main() async { deviceOperatingSystem = DeviceOperatingSystem.ios; - await task(createPlatformServiceDriverTest()); + await task(createChannelsIntegrationTest()); }
diff --git a/dev/devicelab/bin/tasks/platform_channel_test.dart b/dev/devicelab/bin/tasks/channels_integration_test_win.dart similarity index 77% copy from dev/devicelab/bin/tasks/platform_channel_test.dart copy to dev/devicelab/bin/tasks/channels_integration_test_win.dart index d1afc67..8b60289 100644 --- a/dev/devicelab/bin/tasks/platform_channel_test.dart +++ b/dev/devicelab/bin/tasks/channels_integration_test_win.dart
@@ -4,11 +4,11 @@ import 'dart:async'; -import 'package:flutter_devicelab/tasks/perf_tests.dart'; import 'package:flutter_devicelab/framework/adb.dart'; import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/integration_tests.dart'; Future<Null> main() async { deviceOperatingSystem = DeviceOperatingSystem.android; - await task(createPlatformServiceDriverTest()); + await task(createChannelsIntegrationTest()); }
diff --git a/dev/devicelab/bin/tasks/platform_channel_test.dart b/dev/devicelab/bin/tasks/platform_channel_sample_test.dart similarity index 77% rename from dev/devicelab/bin/tasks/platform_channel_test.dart rename to dev/devicelab/bin/tasks/platform_channel_sample_test.dart index d1afc67..38b10b3 100644 --- a/dev/devicelab/bin/tasks/platform_channel_test.dart +++ b/dev/devicelab/bin/tasks/platform_channel_sample_test.dart
@@ -4,11 +4,11 @@ import 'dart:async'; -import 'package:flutter_devicelab/tasks/perf_tests.dart'; import 'package:flutter_devicelab/framework/adb.dart'; import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/integration_tests.dart'; Future<Null> main() async { deviceOperatingSystem = DeviceOperatingSystem.android; - await task(createPlatformServiceDriverTest()); + await task(createPlatformChannelSampleTest()); }
diff --git a/dev/devicelab/bin/tasks/platform_channel_test_ios.dart b/dev/devicelab/bin/tasks/platform_channel_sample_test_ios.dart similarity index 77% rename from dev/devicelab/bin/tasks/platform_channel_test_ios.dart rename to dev/devicelab/bin/tasks/platform_channel_sample_test_ios.dart index 07760fb..9feeaa5 100644 --- a/dev/devicelab/bin/tasks/platform_channel_test_ios.dart +++ b/dev/devicelab/bin/tasks/platform_channel_sample_test_ios.dart
@@ -4,11 +4,11 @@ import 'dart:async'; -import 'package:flutter_devicelab/tasks/perf_tests.dart'; import 'package:flutter_devicelab/framework/adb.dart'; import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/integration_tests.dart'; Future<Null> main() async { deviceOperatingSystem = DeviceOperatingSystem.ios; - await task(createPlatformServiceDriverTest()); + await task(createPlatformChannelSampleTest()); }
diff --git a/dev/devicelab/lib/tasks/integration_tests.dart b/dev/devicelab/lib/tasks/integration_tests.dart new file mode 100644 index 0000000..004e7e5 --- /dev/null +++ b/dev/devicelab/lib/tasks/integration_tests.dart
@@ -0,0 +1,57 @@ +// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import '../framework/adb.dart'; +import '../framework/framework.dart'; +import '../framework/ios.dart'; +import '../framework/utils.dart'; + +TaskFunction createChannelsIntegrationTest() { + return new DriverTest( + '${flutterDirectory.path}/dev/integration_tests/channels', + 'lib/main.dart', + ); +} + +TaskFunction createPlatformChannelSampleTest() { + return new DriverTest( + '${flutterDirectory.path}/examples/platform_channel', + 'test_driver/button_tap.dart', + ); +} + +class DriverTest { + + DriverTest(this.testDirectory, this.testTarget); + + final String testDirectory; + final String testTarget; + + Future<TaskResult> call() { + return inDirectory(testDirectory, () async { + final Device device = await devices.workingDevice; + await device.unlock(); + final String deviceId = device.deviceId; + await flutter('packages', options: <String>['get']); + + if (deviceOperatingSystem == DeviceOperatingSystem.ios) { + await prepareProvisioningCertificates(testDirectory); + // This causes an Xcode project to be created. + await flutter('build', options: <String>['ios', '--profile']); + } + + await flutter('drive', options: <String>[ + '-v', + '-t', + testTarget, + '-d', + deviceId, + ]); + + return new TaskResult.success(null); + }); + } +}
diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index 87da30c..c59f216 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart
@@ -10,14 +10,6 @@ import '../framework/ios.dart'; import '../framework/utils.dart'; - -TaskFunction createPlatformServiceDriverTest() { - return new DriverTest( - '${flutterDirectory.path}/examples/platform_channel', - 'test_driver/button_tap.dart', - ); -} - TaskFunction createComplexLayoutScrollPerfTest() { return new PerfTest( '${flutterDirectory.path}/dev/benchmarks/complex_layout', @@ -175,40 +167,6 @@ } } - -class DriverTest { - - DriverTest(this.testDirectory, this.testTarget); - - final String testDirectory; - final String testTarget; - - Future<TaskResult> call() { - return inDirectory(testDirectory, () async { - final Device device = await devices.workingDevice; - await device.unlock(); - final String deviceId = device.deviceId; - await flutter('packages', options: <String>['get']); - - if (deviceOperatingSystem == DeviceOperatingSystem.ios) { - await prepareProvisioningCertificates(testDirectory); - // This causes an Xcode project to be created. - await flutter('build', options: <String>['ios', '--profile']); - } - - await flutter('drive', options: <String>[ - '-v', - '-t', - testTarget, - '-d', - deviceId, - ]); - - return new TaskResult.success(null); - }); - } -} - class BuildTest { BuildTest(this.testDirectory);
diff --git a/dev/devicelab/manifest.yaml b/dev/devicelab/manifest.yaml index 2aeb98d..b527fd3 100644 --- a/dev/devicelab/manifest.yaml +++ b/dev/devicelab/manifest.yaml
@@ -83,7 +83,13 @@ required_agent_capabilities: ["has-android-device"] flaky: true - platform_channel_test: + channels_integration_test: + description: > + Checks that platform channels work on Android. + stage: devicelab + required_agent_capabilities: ["has-android-device"] + + platform_channel_sample_test: description: > Runs a driver test on the Platform Channel sample app on Android. stage: devicelab @@ -154,7 +160,13 @@ # iOS on-device tests - platform_channel_test_ios: + channels_integration_test_ios: + description: > + Checks that platform channels work on iOS. + stage: devicelab_ios + required_agent_capabilities: ["has-ios-device"] + + platform_channel_sample_test_ios: description: > Runs a driver test on the Platform Channel sample app on iOS. stage: devicelab_ios @@ -207,6 +219,13 @@ # Tests running on Windows host + channels_integration_test_win: + description: > + Checks that platform channels work when app is launched from Windows. + stage: devicelab_win + required_agent_capabilities: ["windows"] + flaky: true + flutter_gallery_win__build: description: > Collects various performance metrics from AOT builds of the Flutter
diff --git a/dev/integration_tests/README.md b/dev/integration_tests/README.md new file mode 100644 index 0000000..b385c93 --- /dev/null +++ b/dev/integration_tests/README.md
@@ -0,0 +1,4 @@ +Automated Flutter integration test suites. Each suite consists of a complete +Flutter app and a `flutter_driver` specification that drives tests from the UI. + +Intended for use with devicelab.
diff --git a/dev/integration_tests/channels/.gitignore b/dev/integration_tests/channels/.gitignore new file mode 100644 index 0000000..eb15c3d --- /dev/null +++ b/dev/integration_tests/channels/.gitignore
@@ -0,0 +1,10 @@ +.DS_Store +.atom/ +.idea +.packages +.pub/ +build/ +ios/.generated/ +packages +pubspec.lock +.flutter-plugins
diff --git a/dev/integration_tests/channels/README.md b/dev/integration_tests/channels/README.md new file mode 100644 index 0000000..6004698 --- /dev/null +++ b/dev/integration_tests/channels/README.md
@@ -0,0 +1,3 @@ +# channels + +Integration test of platform channels.
diff --git a/dev/integration_tests/channels/android/.gitignore b/dev/integration_tests/channels/android/.gitignore new file mode 100644 index 0000000..5c4ef82 --- /dev/null +++ b/dev/integration_tests/channels/android/.gitignore
@@ -0,0 +1,12 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures + +/gradle +/gradlew +/gradlew.bat
diff --git a/dev/integration_tests/channels/android/app/build.gradle b/dev/integration_tests/channels/android/app/build.gradle new file mode 100644 index 0000000..4e2e46b --- /dev/null +++ b/dev/integration_tests/channels/android/app/build.gradle
@@ -0,0 +1,46 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withInputStream { stream -> + localProperties.load(stream) + } +} + +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.") +} + +apply plugin: 'com.android.application' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 25 + buildToolsVersion '25.0.2' + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + 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 { + androidTestCompile 'com.android.support:support-annotations:25.0.0' + androidTestCompile 'com.android.support.test:runner:0.5' + androidTestCompile 'com.android.support.test:rules:0.5' +}
diff --git a/dev/integration_tests/channels/android/app/src/main/AndroidManifest.xml b/dev/integration_tests/channels/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..b63cc17 --- /dev/null +++ b/dev/integration_tests/channels/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,32 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.yourcompany.channels" + android:versionCode="1" + android:versionName="0.0.1"> + + <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="21" /> + + <!-- 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="channels" android:icon="@mipmap/ic_launcher"> + <activity android:name=".MainActivity" + android:launchMode="singleTop" + android:theme="@android:style/Theme.Black.NoTitleBar" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection" + android:hardwareAccelerated="true" + android:windowSoftInputMode="adjustResize"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + </application> +</manifest>
diff --git a/dev/integration_tests/channels/android/app/src/main/java/com/yourcompany/channels/MainActivity.java b/dev/integration_tests/channels/android/app/src/main/java/com/yourcompany/channels/MainActivity.java new file mode 100644 index 0000000..ebd9f18 --- /dev/null +++ b/dev/integration_tests/channels/android/app/src/main/java/com/yourcompany/channels/MainActivity.java
@@ -0,0 +1,142 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package com.yourcompany.channels; + +import java.nio.ByteBuffer; + +import android.os.Bundle; + +import io.flutter.app.FlutterActivity; +import io.flutter.plugin.common.*; +import io.flutter.plugins.PluginRegistry; + +public class MainActivity extends FlutterActivity { + PluginRegistry pluginRegistry; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + pluginRegistry = new PluginRegistry(); + pluginRegistry.registerAll(this); + + setupMessageHandshake(new BasicMessageChannel<>(getFlutterView(), "binary-msg", BinaryCodec.INSTANCE)); + setupMessageHandshake(new BasicMessageChannel<>(getFlutterView(), "string-msg", StringCodec.INSTANCE)); + setupMessageHandshake(new BasicMessageChannel<>(getFlutterView(), "json-msg", JSONMessageCodec.INSTANCE)); + setupMessageHandshake(new BasicMessageChannel<>(getFlutterView(), "std-msg", StandardMessageCodec.INSTANCE)); + setupMethodHandshake(new MethodChannel(getFlutterView(), "json-method", JSONMethodCodec.INSTANCE)); + setupMethodHandshake(new MethodChannel(getFlutterView(), "std-method", StandardMethodCodec.INSTANCE)); + } + + private <T> void setupMessageHandshake(final BasicMessageChannel<T> channel) { + // On message receipt, do a send/reply/send round-trip in the other direction, + // then reply to the first message. + channel.setMessageHandler(new BasicMessageChannel.MessageHandler<T>() { + @Override + public void onMessage(final T message, final BasicMessageChannel.Reply<T> reply) { + final T messageEcho = echo(message); + channel.send(messageEcho, new BasicMessageChannel.Reply<T>() { + @Override + public void reply(T replyMessage) { + channel.send(echo(replyMessage)); + reply.reply(messageEcho); + } + }); + } + }); + } + + // Outgoing ByteBuffer messages must be direct-allocated and payload placed between + // positon 0 and current position. + @SuppressWarnings("unchecked") + private <T> T echo(T message) { + if (message instanceof ByteBuffer) { + final ByteBuffer buffer = (ByteBuffer) message; + final ByteBuffer echo = ByteBuffer.allocateDirect(buffer.remaining()); + echo.put(buffer); + return (T) echo; + } + return message; + } + + private void setupMethodHandshake(final MethodChannel channel) { + channel.setMethodCallHandler(new MethodChannel.MethodCallHandler() { + @Override + public void onMethodCall(final MethodCall methodCall, final MethodChannel.Result result) { + switch (methodCall.method) { + case "success": + doSuccessHandshake(channel, methodCall, result); + break; + case "error": + doErrorHandshake(channel, methodCall, result); + break; + default: + doNotImplementedHandshake(channel, methodCall, result); + break; + + } + } + }); + } + + private void doSuccessHandshake(final MethodChannel channel, final MethodCall methodCall, final MethodChannel.Result result) { + channel.invokeMethod(methodCall.method, methodCall.arguments, new MethodChannel.Result() { + @Override + public void success(Object o) { + channel.invokeMethod(methodCall.method, o); + result.success(methodCall.arguments); + } + + @Override + public void error(String code, String message, Object details) { + throw new AssertionError("Should not be called"); + } + + @Override + public void notImplemented() { + throw new AssertionError("Should not be called"); + } + }); + } + + private void doErrorHandshake(final MethodChannel channel, final MethodCall methodCall, final MethodChannel.Result result) { + channel.invokeMethod(methodCall.method, methodCall.arguments, new MethodChannel.Result() { + @Override + public void success(Object o) { + throw new AssertionError("Should not be called"); + } + + @Override + public void error(String code, String message, Object details) { + channel.invokeMethod(methodCall.method, details); + result.error(code, message, methodCall.arguments); + } + + @Override + public void notImplemented() { + throw new AssertionError("Should not be called"); + } + }); + } + + private void doNotImplementedHandshake(final MethodChannel channel, final MethodCall methodCall, final MethodChannel.Result result) { + channel.invokeMethod(methodCall.method, methodCall.arguments, new MethodChannel.Result() { + @Override + public void success(Object o) { + throw new AssertionError("Should not be called"); + } + + @Override + public void error(String code, String message, Object details) { + throw new AssertionError("Should not be called"); + } + + @Override + public void notImplemented() { + channel.invokeMethod(methodCall.method, null); + result.notImplemented(); + } + }); + } +}
diff --git a/dev/integration_tests/channels/android/app/src/main/java/io/flutter/plugins/PluginRegistry.java b/dev/integration_tests/channels/android/app/src/main/java/io/flutter/plugins/PluginRegistry.java new file mode 100644 index 0000000..92f7a74 --- /dev/null +++ b/dev/integration_tests/channels/android/app/src/main/java/io/flutter/plugins/PluginRegistry.java
@@ -0,0 +1,14 @@ +package io.flutter.plugins; + +import io.flutter.app.FlutterActivity; + + +/** + * Generated file. Do not edit. + */ + +public class PluginRegistry { + + public void registerAll(FlutterActivity activity) { + } +}
diff --git a/dev/integration_tests/channels/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/dev/integration_tests/channels/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..db77bb4 --- /dev/null +++ b/dev/integration_tests/channels/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files differ
diff --git a/dev/integration_tests/channels/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/dev/integration_tests/channels/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..17987b7 --- /dev/null +++ b/dev/integration_tests/channels/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files differ
diff --git a/dev/integration_tests/channels/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/dev/integration_tests/channels/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..09d4391 --- /dev/null +++ b/dev/integration_tests/channels/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files differ
diff --git a/dev/integration_tests/channels/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/dev/integration_tests/channels/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..d5f1c8d --- /dev/null +++ b/dev/integration_tests/channels/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files differ
diff --git a/dev/integration_tests/channels/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/dev/integration_tests/channels/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..4d6372e --- /dev/null +++ b/dev/integration_tests/channels/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ
diff --git a/dev/integration_tests/channels/android/build.gradle b/dev/integration_tests/channels/android/build.gradle new file mode 100644 index 0000000..ee5325d --- /dev/null +++ b/dev/integration_tests/channels/android/build.gradle
@@ -0,0 +1,29 @@ +buildscript { + repositories { + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:2.2.3' + } +} + +allprojects { + repositories { + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} + +task wrapper(type: Wrapper) { + gradleVersion = '2.14.1' +}
diff --git a/dev/integration_tests/channels/android/gradle.properties b/dev/integration_tests/channels/android/gradle.properties new file mode 100644 index 0000000..8bd86f6 --- /dev/null +++ b/dev/integration_tests/channels/android/gradle.properties
@@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1536M
diff --git a/dev/integration_tests/channels/android/settings.gradle b/dev/integration_tests/channels/android/settings.gradle new file mode 100644 index 0000000..115da6c --- /dev/null +++ b/dev/integration_tests/channels/android/settings.gradle
@@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withInputStream { stream -> plugins.load(stream) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +}
diff --git a/dev/integration_tests/channels/ios/.gitignore b/dev/integration_tests/channels/ios/.gitignore new file mode 100644 index 0000000..797c015 --- /dev/null +++ b/dev/integration_tests/channels/ios/.gitignore
@@ -0,0 +1,39 @@ +.idea/ +.vagrant/ +.sconsign.dblite +.svn/ + +.DS_Store +*.swp +profile + +DerivedData/ +build/ + +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 + +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 + +xcuserdata + +*.moved-aside + +*.pyc +*sync/ +Icon? +.tags* + +/Flutter/app.flx +/Flutter/app.zip +/Flutter/App.framework +/Flutter/Flutter.framework +/Flutter/Generated.xcconfig +/ServiceDefinitions.json + +Pods/
diff --git a/dev/integration_tests/channels/ios/Flutter/AppFrameworkInfo.plist b/dev/integration_tests/channels/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..6c2de80 --- /dev/null +++ b/dev/integration_tests/channels/ios/Flutter/AppFrameworkInfo.plist
@@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>en</string> + <key>CFBundleExecutable</key> + <string>App</string> + <key>CFBundleIdentifier</key> + <string>io.flutter.flutter.app</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>App</string> + <key>CFBundlePackageType</key> + <string>FMWK</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>1.0</string> + <key>UIRequiredDeviceCapabilities</key> + <array> + <string>arm64</string> + </array> + <key>MinimumOSVersion</key> + <string>8.0</string> +</dict> +</plist>
diff --git a/dev/integration_tests/channels/ios/Flutter/Debug.xcconfig b/dev/integration_tests/channels/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..72c15fd --- /dev/null +++ b/dev/integration_tests/channels/ios/Flutter/Debug.xcconfig
@@ -0,0 +1,4 @@ +#include "Generated.xcconfig" +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" + +#include "TestConfig.xcconfig"
diff --git a/dev/integration_tests/channels/ios/Flutter/Release.xcconfig b/dev/integration_tests/channels/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..8d3ed2b --- /dev/null +++ b/dev/integration_tests/channels/ios/Flutter/Release.xcconfig
@@ -0,0 +1,4 @@ +#include "Generated.xcconfig" +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" + +#include "TestConfig.xcconfig"
diff --git a/dev/integration_tests/channels/ios/Flutter/TestConfig.xcconfig b/dev/integration_tests/channels/ios/Flutter/TestConfig.xcconfig new file mode 100644 index 0000000..6c52ef8 --- /dev/null +++ b/dev/integration_tests/channels/ios/Flutter/TestConfig.xcconfig
@@ -0,0 +1,5 @@ +ProvisioningStyle=Manual +CODE_SIGN_IDENTITY=iPhone Developer +PROVISIONING_PROFILE=Xcode Managed Profile +DEVELOPMENT_TEAM=... +PROVISIONING_PROFILE_SPECIFIER=...
diff --git a/dev/integration_tests/channels/ios/Podfile b/dev/integration_tests/channels/ios/Podfile new file mode 100644 index 0000000..74b3de0 --- /dev/null +++ b/dev/integration_tests/channels/ios/Podfile
@@ -0,0 +1,38 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +if ENV['FLUTTER_FRAMEWORK_DIR'] == nil + abort('Please set FLUTTER_FRAMEWORK_DIR to the directory containing Flutter.framework') +end + +target 'Runner' do + use_frameworks! + + # Pods for Runner + + # Flutter Pods + pod 'Flutter', :path => ENV['FLUTTER_FRAMEWORK_DIR'] + + if File.exists? '../.flutter-plugins' + flutter_root = File.expand_path('..') + File.foreach('../.flutter-plugins') { |line| + plugin = line.split(pattern='=') + if plugin.length == 2 + name = plugin[0].strip() + path = plugin[1].strip() + resolved_path = File.expand_path("#{path}/ios", flutter_root) + pod name, :path => resolved_path + else + puts "Invalid plugin specification: #{line}" + end + } + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['ENABLE_BITCODE'] = 'NO' + end + end +end
diff --git a/dev/integration_tests/channels/ios/Podfile.lock b/dev/integration_tests/channels/ios/Podfile.lock new file mode 100644 index 0000000..8e25faa --- /dev/null +++ b/dev/integration_tests/channels/ios/Podfile.lock
@@ -0,0 +1,16 @@ +PODS: + - Flutter (1.0.0) + +DEPENDENCIES: + - Flutter (from `/Users/mravn/github/engine/src/out/ios_debug_unopt`) + +EXTERNAL SOURCES: + Flutter: + :path: "/Users/mravn/github/engine/src/out/ios_debug_unopt" + +SPEC CHECKSUMS: + Flutter: d674e78c937094a75ac71dd77e921e840bea3dbf + +PODFILE CHECKSUM: cc70c01bca487bebd110b87397f017f3b76a89f1 + +COCOAPODS: 1.2.1
diff --git a/dev/integration_tests/channels/ios/Runner.xcodeproj/project.pbxproj b/dev/integration_tests/channels/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..b61088c --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner.xcodeproj/project.pbxproj
@@ -0,0 +1,505 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* PluginRegistry.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* PluginRegistry.m */; }; + 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, ); }; }; + 913134F849F6C8DEAC837F96 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C803412E9584DEAC0259A174 /* Pods_Runner.framework */; }; + 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 */; }; + 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB31CF90195004384FC /* Generated.xcconfig */; }; + 9740EEBB1CF902C7004384FC /* app.flx in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB71CF902C7004384FC /* app.flx */; }; + 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; + 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, + 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* PluginRegistry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PluginRegistry.h; sourceTree = "<group>"; }; + 1498D2331E8E89220040F4C2 /* PluginRegistry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PluginRegistry.m; sourceTree = "<group>"; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; }; + 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; }; + 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; }; + 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; }; + 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>"; }; + 9740EEB71CF902C7004384FC /* app.flx */ = {isa = PBXFileReference; lastKnownFileType = file; name = app.flx; path = Flutter/app.flx; sourceTree = "<group>"; }; + 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; + C803412E9584DEAC0259A174 /* 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 */, + 913134F849F6C8DEAC837F96 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 840012C8B5EDBCF56B0E4AC1 /* Pods */ = { + isa = PBXGroup; + children = ( + ); + name = Pods; + sourceTree = "<group>"; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 9740EEB71CF902C7004384FC /* app.flx */, + 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 */, + 840012C8B5EDBCF56B0E4AC1 /* Pods */, + CF3B75C9A7D2FA2A4C99F110 /* Frameworks */, + ); + sourceTree = "<group>"; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = "<group>"; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, + 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* PluginRegistry.h */, + 1498D2331E8E89220040F4C2 /* PluginRegistry.m */, + ); + path = Runner; + sourceTree = "<group>"; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 97C146F21CF9000F007C117D /* main.m */, + ); + name = "Supporting Files"; + sourceTree = "<group>"; + }; + CF3B75C9A7D2FA2A4C99F110 /* Frameworks */ = { + isa = PBXGroup; + children = ( + C803412E9584DEAC0259A174 /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + AB1344B0443C71CD721E1BB7 /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */, + 532EA9D341340B1DCD08293D /* [CP] Copy Pods Resources */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + ORGANIZATIONNAME = "The Chromium Authors"; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + DevelopmentTeam = AQ7UHDBEXJ; + ProvisioningStyle = Automatic; + }; + }; + }; + 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 = ( + 9740EEBB1CF902C7004384FC /* app.flx in Resources */, + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; + }; + 532EA9D341340B1DCD08293D /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + 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"; + }; + AB1344B0443C71CD721E1BB7 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + 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"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, + 97C146F31CF9000F007C117D /* main.m in Sources */, + 1498D2341E8E89220040F4C2 /* PluginRegistry.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_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + 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_BOOL_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ARCHS = arm64; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEVELOPMENT_TEAM = AQ7UHDBEXJ; + 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.yourcompany.channels; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + PROVISIONING_PROFILE_SPECIFIER = ""; + ProvisioningStyle = Automatic; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ARCHS = arm64; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEVELOPMENT_TEAM = AQ7UHDBEXJ; + 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.yourcompany.channels; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + PROVISIONING_PROFILE_SPECIFIER = ""; + ProvisioningStyle = Automatic; + }; + 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 */; +}
diff --git a/dev/integration_tests/channels/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/dev/integration_tests/channels/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Workspace + version = "1.0"> + <FileRef + location = "group:Runner.xcodeproj"> + </FileRef> + <FileRef + location = "group:Pods/Pods.xcodeproj"> + </FileRef> +</Workspace>
diff --git a/dev/integration_tests/channels/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/dev/integration_tests/channels/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..1c95807 --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "0830" + version = "1.3"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "YES"> + <BuildActionEntries> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "YES" + buildForArchiving = "YES" + buildForAnalyzing = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "97C146ED1CF9000F007C117D" + BuildableName = "Runner.app" + BlueprintName = "Runner" + ReferencedContainer = "container:Runner.xcodeproj"> + </BuildableReference> + </BuildActionEntry> + </BuildActionEntries> + </BuildAction> + <TestAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + shouldUseLaunchSchemeArgsEnv = "YES"> + <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" + 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>
diff --git a/dev/integration_tests/channels/ios/Runner.xcworkspace/contents.xcworkspacedata b/dev/integration_tests/channels/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Workspace + version = "1.0"> + <FileRef + location = "group:Runner.xcodeproj"> + </FileRef> + <FileRef + location = "group:Pods/Pods.xcodeproj"> + </FileRef> +</Workspace>
diff --git a/dev/integration_tests/channels/ios/Runner/AppDelegate.h b/dev/integration_tests/channels/ios/Runner/AppDelegate.h new file mode 100644 index 0000000..138b680 --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner/AppDelegate.h
@@ -0,0 +1,10 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import <UIKit/UIKit.h> +#import <Flutter/Flutter.h> + +@interface AppDelegate : FlutterAppDelegate + +@end
diff --git a/dev/integration_tests/channels/ios/Runner/AppDelegate.m b/dev/integration_tests/channels/ios/Runner/AppDelegate.m new file mode 100644 index 0000000..94c06d8 --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner/AppDelegate.m
@@ -0,0 +1,99 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "AppDelegate.h" +#include "PluginRegistry.h" + +@implementation AppDelegate { + PluginRegistry *plugins; +} + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // Override point for customization after application launch. + FlutterViewController *flutterController = + (FlutterViewController *)self.window.rootViewController; + plugins = [[PluginRegistry alloc] initWithController:flutterController]; + + [self setupMessagingHandshakeOnChannel: + [FlutterBasicMessageChannel messageChannelWithName:@"binary-msg" + binaryMessenger:flutterController + codec:[FlutterBinaryCodec sharedInstance]]]; + [self setupMessagingHandshakeOnChannel: + [FlutterBasicMessageChannel messageChannelWithName:@"string-msg" + binaryMessenger:flutterController + codec:[FlutterStringCodec sharedInstance]]]; + [self setupMessagingHandshakeOnChannel: + [FlutterBasicMessageChannel messageChannelWithName:@"json-msg" + binaryMessenger:flutterController + codec:[FlutterJSONMessageCodec sharedInstance]]]; + [self setupMessagingHandshakeOnChannel: + [FlutterBasicMessageChannel messageChannelWithName:@"std-msg" + binaryMessenger:flutterController + codec:[FlutterStandardMessageCodec sharedInstance]]]; + [self setupMethodCallSuccessHandshakeOnChannel: + [FlutterMethodChannel methodChannelWithName:@"json-method" + binaryMessenger:flutterController + codec:[FlutterJSONMethodCodec sharedInstance]]]; + [self setupMethodCallSuccessHandshakeOnChannel: + [FlutterMethodChannel methodChannelWithName:@"std-method" + binaryMessenger:flutterController + codec:[FlutterStandardMethodCodec sharedInstance]]]; + return YES; +} + +- (void)setupMessagingHandshakeOnChannel:(FlutterBasicMessageChannel*)channel { + [channel setMessageHandler:^(id message, FlutterReply reply) { + [channel sendMessage:message reply:^(id messageReply) { + [channel sendMessage:messageReply]; + reply(message); + }]; + }]; +} + +- (void)setupMethodCallSuccessHandshakeOnChannel:(FlutterMethodChannel*)channel { + [channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { + if ([call.method isEqual:@"success"]) { + [channel invokeMethod:call.method arguments:call.arguments result:^(id value) { + [channel invokeMethod:call.method arguments:value]; + result(call.arguments); + }]; + } else if ([call.method isEqual:@"error"]) { + [channel invokeMethod:call.method arguments:call.arguments result:^(id value) { + FlutterError* error = (FlutterError*) value; + [channel invokeMethod:call.method arguments:error.details]; + result(error); + }]; + } else { + [channel invokeMethod:call.method arguments:call.arguments result:^(id value) { + NSAssert(value == FlutterMethodNotImplemented, @"Result must be not implemented"); + [channel invokeMethod:call.method arguments:nil]; + result(FlutterMethodNotImplemented); + }]; + } + }]; +} + +- (void)applicationWillResignActive:(UIApplication *)application { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. +} + +- (void)applicationDidEnterBackground:(UIApplication *)application { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + +- (void)applicationWillEnterForeground:(UIApplication *)application { + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. +} + +- (void)applicationDidBecomeActive:(UIApplication *)application { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. +} + +- (void)applicationWillTerminate:(UIApplication *)application { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + +@end
diff --git a/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d22f10b --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,116 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +}
diff --git a/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..28c6bf0 --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files differ
diff --git a/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..2ccbfd9 --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files differ
diff --git a/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..f091b6b --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files differ
diff --git a/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..4cde121 --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files differ
diff --git a/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..d0ef06e --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files differ
diff --git a/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..dcdc230 --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files differ
diff --git a/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..2ccbfd9 --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files differ
diff --git a/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..c8f9ed8 --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files differ
diff --git a/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..a6d6b86 --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files differ
diff --git a/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..a6d6b86 --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files differ
diff --git a/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..75b2d16 --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files differ
diff --git a/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..c4df70d --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files differ
diff --git a/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..6a84f41 --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files differ
diff --git a/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..d0e1f58 --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files differ
diff --git a/dev/integration_tests/channels/ios/Runner/Base.lproj/LaunchScreen.storyboard b/dev/integration_tests/channels/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..ebf48f6 --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM"> + <dependencies> + <deployment identifier="iOS"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/> + </dependencies> + <scenes> + <!--View Controller--> + <scene sceneID="EHf-IW-A2E"> + <objects> + <viewController id="01J-lp-oVM" sceneMemberID="viewController"> + <layoutGuides> + <viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/> + <viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/> + </layoutGuides> + <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3"> + <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> + </view> + </viewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="53" y="375"/> + </scene> + </scenes> +</document>
diff --git a/dev/integration_tests/channels/ios/Runner/Base.lproj/Main.storyboard b/dev/integration_tests/channels/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner/Base.lproj/Main.storyboard
@@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r"> + <dependencies> + <deployment identifier="iOS"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/> + </dependencies> + <scenes> + <!--Flutter View Controller--> + <scene sceneID="tne-QT-ifu"> + <objects> + <viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController"> + <layoutGuides> + <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/> + <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/> + </layoutGuides> + <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC"> + <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> + </view> + </viewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/> + </objects> + </scene> + </scenes> +</document>
diff --git a/dev/integration_tests/channels/ios/Runner/Info.plist b/dev/integration_tests/channels/ios/Runner/Info.plist new file mode 100644 index 0000000..04cb09d --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner/Info.plist
@@ -0,0 +1,49 @@ +<?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>channels</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>1</string> + <key>LSRequiresIPhoneOS</key> + <true/> + <key>UILaunchStoryboardName</key> + <string>LaunchScreen</string> + <key>UIMainStoryboardFile</key> + <string>Main</string> + <key>UIRequiredDeviceCapabilities</key> + <array> + <string>arm64</string> + </array> + <key>UISupportedInterfaceOrientations</key> + <array> + <string>UIInterfaceOrientationPortrait</string> + <string>UIInterfaceOrientationLandscapeLeft</string> + <string>UIInterfaceOrientationLandscapeRight</string> + </array> + <key>UISupportedInterfaceOrientations~ipad</key> + <array> + <string>UIInterfaceOrientationPortrait</string> + <string>UIInterfaceOrientationPortraitUpsideDown</string> + <string>UIInterfaceOrientationLandscapeLeft</string> + <string>UIInterfaceOrientationLandscapeRight</string> + </array> + <key>UIViewControllerBasedStatusBarAppearance</key> + <false/> +</dict> +</plist>
diff --git a/dev/integration_tests/channels/ios/Runner/PluginRegistry.h b/dev/integration_tests/channels/ios/Runner/PluginRegistry.h new file mode 100644 index 0000000..df039db --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner/PluginRegistry.h
@@ -0,0 +1,18 @@ +// +// Generated file. Do not edit. +// + +#ifndef PluginRegistry_h +#define PluginRegistry_h + +#import <Flutter/Flutter.h> + + +@interface PluginRegistry : NSObject + + +- (instancetype)initWithController:(FlutterViewController *)controller; + +@end + +#endif /* PluginRegistry_h */
diff --git a/dev/integration_tests/channels/ios/Runner/PluginRegistry.m b/dev/integration_tests/channels/ios/Runner/PluginRegistry.m new file mode 100644 index 0000000..0a34729 --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner/PluginRegistry.m
@@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +#import "PluginRegistry.h" + +@implementation PluginRegistry + +- (instancetype)initWithController:(FlutterViewController *)controller { + if (self = [super init]) { + } + return self; +} + +@end
diff --git a/dev/integration_tests/channels/ios/Runner/main.m b/dev/integration_tests/channels/ios/Runner/main.m new file mode 100644 index 0000000..945818b --- /dev/null +++ b/dev/integration_tests/channels/ios/Runner/main.m
@@ -0,0 +1,14 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import <UIKit/UIKit.h> +#import <Flutter/Flutter.h> +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, + NSStringFromClass([AppDelegate class])); + } +}
diff --git a/dev/integration_tests/channels/lib/main.dart b/dev/integration_tests/channels/lib/main.dart new file mode 100644 index 0000000..025f3e1 --- /dev/null +++ b/dev/integration_tests/channels/lib/main.dart
@@ -0,0 +1,193 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:flutter_driver/driver_extension.dart'; + +import 'src/basic_messaging.dart'; +import 'src/method_calls.dart'; +import 'src/test_step.dart'; + +void main() { + enableFlutterDriverExtension(); + runApp(new TestApp()); +} + +class TestApp extends StatefulWidget { + @override + _TestAppState createState() => new _TestAppState(); +} + +class _TestAppState extends State<TestApp> { + static final List<dynamic> aList = <dynamic>[ + false, + 0, + 0.0, + 'hello', + <dynamic>[ + <String, dynamic>{'key': 42} + ], + ]; + static final Map<String, dynamic> aMap = <String, dynamic>{ + 'a': false, + 'b': 0, + 'c': 0.0, + 'd': 'hello', + 'e': <dynamic>[ + <String, dynamic>{'key': 42} + ] + }; + static final Uint8List someUint8s = new Uint8List.fromList(<int>[ + 0xBA, + 0x5E, + 0xBA, + 0x11, + ]); + static final Int32List someInt32s = new Int32List.fromList(<int>[ + -0x7fffffff - 1, + 0, + 0x7fffffff, + ]); + static final Int64List someInt64s = new Int64List.fromList(<int>[ + -0x7fffffffffffffff - 1, + 0, + 0x7fffffffffffffff, + ]); + static final Float64List someFloat64s = + new Float64List.fromList(<double>[ + double.NAN, + double.NEGATIVE_INFINITY, + -double.MAX_FINITE, + -double.MIN_POSITIVE, + -0.0, + 0.0, + double.MIN_POSITIVE, + double.MAX_FINITE, + double.INFINITY, + ]); + static final List<TestStep> steps = <TestStep>[ + () => methodCallJsonSuccessHandshake(null), + () => methodCallJsonSuccessHandshake(true), + () => methodCallJsonSuccessHandshake(7), + () => methodCallJsonSuccessHandshake('world'), + () => methodCallJsonSuccessHandshake(aList), + () => methodCallJsonSuccessHandshake(aMap), + () => methodCallJsonNotImplementedHandshake(), + () => methodCallStandardSuccessHandshake(null), + () => methodCallStandardSuccessHandshake(true), + () => methodCallStandardSuccessHandshake(7), + () => methodCallStandardSuccessHandshake('world'), + () => methodCallStandardSuccessHandshake(aList), + () => methodCallStandardSuccessHandshake(aMap), + () => methodCallJsonErrorHandshake(null), + () => methodCallJsonErrorHandshake('world'), + () => methodCallStandardErrorHandshake(null), + () => methodCallStandardErrorHandshake('world'), + () => methodCallStandardNotImplementedHandshake(), + () => basicBinaryHandshake(null), + () => basicBinaryHandshake(new ByteData(0)), + () => basicBinaryHandshake(new ByteData(4)..setUint32(0, 0x12345678)), + () => basicStringHandshake('hello, world'), + () => basicStringHandshake('hello \u263A \u{1f602} unicode'), + () => basicStringHandshake(''), + () => basicStringHandshake(null), + () => basicJsonHandshake(null), + () => basicJsonHandshake(true), + () => basicJsonHandshake(false), + () => basicJsonHandshake(0), + () => basicJsonHandshake(-7), + () => basicJsonHandshake(7), + () => basicJsonHandshake(1 << 32), + () => basicJsonHandshake(1 << 56), + () => basicJsonHandshake(0.0), + () => basicJsonHandshake(-7.0), + () => basicJsonHandshake(7.0), + () => basicJsonHandshake(''), + () => basicJsonHandshake('hello, world'), + () => basicJsonHandshake('hello, "world"'), + () => basicJsonHandshake('hello \u263A \u{1f602} unicode'), + () => basicJsonHandshake(<dynamic>[]), + () => basicJsonHandshake(aList), + () => basicJsonHandshake(<String, dynamic>{}), + () => basicJsonHandshake(aMap), + () => basicStandardHandshake(null), + () => basicStandardHandshake(true), + () => basicStandardHandshake(false), + () => basicStandardHandshake(0), + () => basicStandardHandshake(-7), + () => basicStandardHandshake(7), + () => basicStandardHandshake(1 << 32), + () => basicStandardHandshake(1 << 64), + () => basicStandardHandshake(1 << 128), + () => basicStandardHandshake(0.0), + () => basicStandardHandshake(-7.0), + () => basicStandardHandshake(7.0), + () => basicStandardHandshake(''), + () => basicStandardHandshake('hello, world'), + () => basicStandardHandshake('hello \u263A \u{1f602} unicode'), + () => basicStandardHandshake(someUint8s), + () => basicStandardHandshake(someInt32s), + () => basicStandardHandshake(someInt64s), + () => basicStandardHandshake(someFloat64s), + () => basicStandardHandshake(<dynamic>[]), + () => basicStandardHandshake(aList), + () => basicStandardHandshake(<String, dynamic>{}), + () => basicStandardHandshake(<dynamic, dynamic>{7: true, false: -7}), + () => basicStandardHandshake(aMap), + () => basicBinaryMessageToUnknownChannel(), + () => basicStringMessageToUnknownChannel(), + () => basicJsonMessageToUnknownChannel(), + () => basicStandardMessageToUnknownChannel(), + ]; + Future<TestStepResult> _result; + int _step = 0; + + @override + void initState() { + super.initState(); + } + + void _executeNextStep() { + setState(() { + if (_step < steps.length) + _result = steps[_step++](); + else + _result = new Future<TestStepResult>.value(TestStepResult.complete); + }); + } + + Widget _buildTestResultWidget( + BuildContext context, + AsyncSnapshot<TestStepResult> snapshot, + ) { + return new TestStepResult.fromSnapshot(snapshot).asWidget(context); + } + + @override + Widget build(BuildContext context) { + return new MaterialApp( + title: 'Channels Test', + home: new Scaffold( + appBar: new AppBar( + title: const Text('Channels Test'), + ), + body: new Padding( + padding: const EdgeInsets.all(20.0), + child: new FutureBuilder<TestStepResult>( + future: _result, + builder: _buildTestResultWidget, + ), + ), + floatingActionButton: new FloatingActionButton( + key: const ValueKey<String>('step'), + onPressed: _executeNextStep, + child: new Icon(Icons.navigate_next), + ), + ), + ); + } +}
diff --git a/dev/integration_tests/channels/lib/src/basic_messaging.dart b/dev/integration_tests/channels/lib/src/basic_messaging.dart new file mode 100644 index 0000000..f2105a8 --- /dev/null +++ b/dev/integration_tests/channels/lib/src/basic_messaging.dart
@@ -0,0 +1,144 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'dart:typed_data'; +import 'package:flutter/services.dart'; +import 'test_step.dart'; + +Future<TestStepResult> basicBinaryHandshake(ByteData message) async { + const BasicMessageChannel<ByteData> channel = + const BasicMessageChannel<ByteData>( + 'binary-msg', + const BinaryCodec(), + ); + return _basicMessageHandshake<ByteData>( + 'Binary >${toString(message)}<', channel, message); +} + +Future<TestStepResult> basicStringHandshake(String message) async { + const BasicMessageChannel<String> channel = const BasicMessageChannel<String>( + 'string-msg', + const StringCodec(), + ); + return _basicMessageHandshake<String>('String >$message<', channel, message); +} + +Future<TestStepResult> basicJsonHandshake(dynamic message) async { + const BasicMessageChannel<dynamic> channel = + const BasicMessageChannel<dynamic>( + 'json-msg', + const JSONMessageCodec(), + ); + return _basicMessageHandshake<dynamic>('JSON >$message<', channel, message); +} + +Future<TestStepResult> basicStandardHandshake(dynamic message) async { + const BasicMessageChannel<dynamic> channel = + const BasicMessageChannel<dynamic>( + 'std-msg', + const StandardMessageCodec(), + ); + return _basicMessageHandshake<dynamic>( + 'Standard >${toString(message)}<', channel, message); +} + +Future<TestStepResult> basicBinaryMessageToUnknownChannel() async { + const BasicMessageChannel<ByteData> channel = + const BasicMessageChannel<ByteData>( + 'binary-unknown', + const BinaryCodec(), + ); + return _basicMessageToUnknownChannel<ByteData>('Binary', channel); +} + +Future<TestStepResult> basicStringMessageToUnknownChannel() async { + const BasicMessageChannel<String> channel = const BasicMessageChannel<String>( + 'string-unknown', + const StringCodec(), + ); + return _basicMessageToUnknownChannel<String>('String', channel); +} + +Future<TestStepResult> basicJsonMessageToUnknownChannel() async { + const BasicMessageChannel<dynamic> channel = + const BasicMessageChannel<dynamic>( + 'json-unknown', + const JSONMessageCodec(), + ); + return _basicMessageToUnknownChannel<dynamic>('JSON', channel); +} + +Future<TestStepResult> basicStandardMessageToUnknownChannel() async { + const BasicMessageChannel<dynamic> channel = + const BasicMessageChannel<dynamic>( + 'std-unknown', + const StandardMessageCodec(), + ); + return _basicMessageToUnknownChannel<dynamic>('Standard', channel); +} + +/// Sends the specified message to the platform, doing a +/// receive message/send reply/receive reply echo handshake initiated by the +/// platform, then expecting a reply echo to the original message. +/// +/// Fails, if an error occurs, or if any message seen is not deeply equal to +/// the original message. +Future<TestStepResult> _basicMessageHandshake<T>( + String description, + BasicMessageChannel<T> channel, + T message, +) async { + final List<dynamic> received = <dynamic>[]; + channel.setMessageHandler((T message) async { + received.add(message); + return message; + }); + dynamic messageEcho = nothing; + dynamic error = nothing; + try { + messageEcho = await channel.send(message); + } catch (e) { + error = e; + } + return resultOfHandshake( + 'Basic message handshake', + description, + message, + received, + messageEcho, + error, + ); +} + +/// Sends a message on a channel that no one listens on. +Future<TestStepResult> _basicMessageToUnknownChannel<T>( + String description, + BasicMessageChannel<T> channel, +) async { + dynamic messageEcho = nothing; + dynamic error = nothing; + try { + messageEcho = await channel.send(null); + } catch (e) { + error = e; + } + return resultOfHandshake( + 'Message on unknown channel', + description, + null, + <dynamic>[null, null], + messageEcho, + error, + ); +} + +String toString(dynamic message) { + if (message is ByteData) + return message.buffer + .asUint8List(message.offsetInBytes, message.lengthInBytes) + .toString(); + else + return '$message'; +}
diff --git a/dev/integration_tests/channels/lib/src/method_calls.dart b/dev/integration_tests/channels/lib/src/method_calls.dart new file mode 100644 index 0000000..7db46cd --- /dev/null +++ b/dev/integration_tests/channels/lib/src/method_calls.dart
@@ -0,0 +1,133 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'package:flutter/services.dart'; +import 'test_step.dart'; + +Future<TestStepResult> methodCallJsonSuccessHandshake(dynamic payload) async { + const MethodChannel channel = + const MethodChannel('json-method', const JSONMethodCodec()); + return _methodCallSuccessHandshake( + 'JSON success($payload)', channel, payload); +} + +Future<TestStepResult> methodCallJsonErrorHandshake(dynamic payload) async { + const MethodChannel channel = + const MethodChannel('json-method', const JSONMethodCodec()); + return _methodCallErrorHandshake('JSON error($payload)', channel, payload); +} + +Future<TestStepResult> methodCallJsonNotImplementedHandshake() async { + const MethodChannel channel = + const MethodChannel('json-method', const JSONMethodCodec()); + return _methodCallNotImplementedHandshake('JSON notImplemented()', channel); +} + +Future<TestStepResult> methodCallStandardSuccessHandshake( + dynamic payload) async { + const MethodChannel channel = + const MethodChannel('std-method', const StandardMethodCodec()); + return _methodCallSuccessHandshake( + 'Standard success($payload)', channel, payload); +} + +Future<TestStepResult> methodCallStandardErrorHandshake(dynamic payload) async { + const MethodChannel channel = + const MethodChannel('std-method', const StandardMethodCodec()); + return _methodCallErrorHandshake( + 'Standard error($payload)', channel, payload); +} + +Future<TestStepResult> methodCallStandardNotImplementedHandshake() async { + const MethodChannel channel = + const MethodChannel('std-method', const StandardMethodCodec()); + return _methodCallNotImplementedHandshake( + 'Standard notImplemented()', channel); +} + +Future<TestStepResult> _methodCallSuccessHandshake( + String description, + MethodChannel channel, + dynamic arguments, +) async { + final List<dynamic> received = <dynamic>[]; + channel.setMethodCallHandler((MethodCall call) async { + received.add(call.arguments); + return call.arguments; + }); + dynamic result = nothing; + dynamic error = nothing; + try { + result = await channel.invokeMethod('success', arguments); + } catch (e) { + error = e; + } + return resultOfHandshake( + 'Method call success handshake', + description, + arguments, + received, + result, + error, + ); +} + +Future<TestStepResult> _methodCallErrorHandshake( + String description, + MethodChannel channel, + dynamic arguments, +) async { + final List<dynamic> received = <dynamic>[]; + channel.setMethodCallHandler((MethodCall call) async { + received.add(call.arguments); + throw new PlatformException( + code: 'error', message: null, details: arguments); + }); + dynamic errorDetails = nothing; + dynamic error = nothing; + try { + error = await channel.invokeMethod('error', arguments); + } on PlatformException catch (e) { + errorDetails = e.details; + } catch (e) { + error = e; + } + return resultOfHandshake( + 'Method call error handshake', + description, + arguments, + received, + errorDetails, + error, + ); +} + +Future<TestStepResult> _methodCallNotImplementedHandshake( + String description, + MethodChannel channel, +) async { + final List<dynamic> received = <dynamic>[]; + channel.setMethodCallHandler((MethodCall call) async { + received.add(call.arguments); + throw new MissingPluginException(); + }); + dynamic result = nothing; + dynamic error = nothing; + try { + error = await channel.invokeMethod('notImplemented'); + } on MissingPluginException { + result = null; + } catch (e) { + error = e; + } + return resultOfHandshake( + 'Method call not implemented handshake', + description, + null, + received, + result, + error, + ); +}
diff --git a/dev/integration_tests/channels/lib/src/test_step.dart b/dev/integration_tests/channels/lib/src/test_step.dart new file mode 100644 index 0000000..1f65880 --- /dev/null +++ b/dev/integration_tests/channels/lib/src/test_step.dart
@@ -0,0 +1,168 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; + +enum TestStatus { ok, pending, failed, complete } + +typedef Future<TestStepResult> TestStep(); + +const String nothing = '-'; + +/// Result of a test step checking a nested communication handshake +/// between the Flutter app and the platform: +/// +/// - The Flutter app sends a message to the platform. +/// - The platform, on receipt, echos the message back to Flutter in a separate message. +/// - The Flutter app records the incoming message echo and replies. +/// - The platform, on receipt of reply, echos the reply back to Flutter in a separate message. +/// - The Flutter app records the incoming reply echo. +/// - The platform finally replies to the original message with another echo. +class TestStepResult { + static const TextStyle bold = const TextStyle(fontWeight: FontWeight.bold); + static const TestStepResult complete = const TestStepResult( + 'Test complete', + nothing, + TestStatus.complete, + ); + + const TestStepResult( + this.name, + this.description, + this.status, { + this.messageSent = nothing, + this.messageEcho = nothing, + this.messageReceived = nothing, + this.replyEcho = nothing, + this.error = nothing, + }); + + factory TestStepResult.fromSnapshot(AsyncSnapshot<TestStepResult> snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.none: + return const TestStepResult('Not started', nothing, TestStatus.ok); + case ConnectionState.waiting: + return const TestStepResult('Executing', nothing, TestStatus.pending); + case ConnectionState.done: + if (snapshot.hasData) { + return snapshot.data; + } else { + final TestStepResult result = snapshot.error; + return result; + } + break; + default: + throw 'Unsupported state ${snapshot.connectionState}'; + } + } + + final String name; + final String description; + final TestStatus status; + final dynamic messageSent; + final dynamic messageEcho; + final dynamic messageReceived; + final dynamic replyEcho; + final dynamic error; + + Widget asWidget(BuildContext context) { + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: <Widget>[ + new Text('Step: $name', style: bold), + new Text(description), + const Text(' '), + new Text('Msg sent: ${_toString(messageSent)}'), + new Text('Msg rvcd: ${_toString(messageReceived)}'), + new Text('Reply echo: ${_toString(replyEcho)}'), + new Text('Msg echo: ${_toString(messageEcho)}'), + new Text('Error: ${_toString(error)}'), + const Text(' '), + new Text( + status.toString().substring('TestStatus.'.length), + key: new ValueKey<String>( + status == TestStatus.pending ? 'nostatus' : 'status'), + style: bold, + ), + ], + ); + } +} + +Future<TestStepResult> resultOfHandshake( + String name, + String description, + dynamic message, + List<dynamic> received, + dynamic messageEcho, + dynamic error, +) async { + assert(message != nothing); + while (received.length < 2) received.add(nothing); + TestStatus status; + if (!_deepEquals(messageEcho, message) || + received.length != 2 || + !_deepEquals(received[0], message) || + !_deepEquals(received[1], message)) { + status = TestStatus.failed; + } else if (error != nothing) { + status = TestStatus.failed; + } else { + status = TestStatus.ok; + } + return new TestStepResult( + name, + description, + status, + messageSent: message, + messageEcho: messageEcho, + messageReceived: received[0], + replyEcho: received[1], + error: error, + ); +} + +String _toString(dynamic message) { + if (message is ByteData) + return message.buffer + .asUint8List(message.offsetInBytes, message.lengthInBytes) + .toString(); + else + return '$message'; +} + +bool _deepEquals(dynamic a, dynamic b) { + if (a == b) return true; + if (a is double && a.isNaN) return b is double && b.isNaN; + if (a is ByteData) return b is ByteData && _deepEqualsByteData(a, b); + if (a is List) return b is List && _deepEqualsList(a, b); + if (a is Map) return b is Map && _deepEqualsMap(a, b); + return false; +} + +bool _deepEqualsByteData(ByteData a, ByteData b) { + return _deepEqualsList( + a.buffer.asUint8List(a.offsetInBytes, a.lengthInBytes), + b.buffer.asUint8List(b.offsetInBytes, b.lengthInBytes), + ); +} + +bool _deepEqualsList(List<dynamic> a, List<dynamic> b) { + if (a.length != b.length) return false; + for (int i = 0; i < a.length; i++) { + if (!_deepEquals(a[i], b[i])) return false; + } + return true; +} + +bool _deepEqualsMap(Map<dynamic, dynamic> a, Map<dynamic, dynamic> b) { + if (a.length != b.length) return false; + for (dynamic key in a.keys) { + if (!b.containsKey(key) || !_deepEquals(a[key], b[key])) return false; + } + return true; +}
diff --git a/dev/integration_tests/channels/pubspec.yaml b/dev/integration_tests/channels/pubspec.yaml new file mode 100644 index 0000000..3c26fdd --- /dev/null +++ b/dev/integration_tests/channels/pubspec.yaml
@@ -0,0 +1,10 @@ +name: channels +description: Integration test for platform channels. + +dependencies: + flutter: + sdk: flutter + flutter_driver: + sdk: flutter +flutter: + uses-material-design: true
diff --git a/dev/integration_tests/channels/test_driver/main_test.dart b/dev/integration_tests/channels/test_driver/main_test.dart new file mode 100644 index 0000000..1048c69 --- /dev/null +++ b/dev/integration_tests/channels/test_driver/main_test.dart
@@ -0,0 +1,34 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_driver/flutter_driver.dart'; +import 'package:test/test.dart'; + +void main() { + group('channel suite', () { + FlutterDriver driver; + + setUpAll(() async { + driver = await FlutterDriver.connect(); + }); + + test('step through', () async { + final SerializableFinder stepButton = find.byValueKey('step'); + final SerializableFinder statusField = find.byValueKey('status'); + int step = 0; + while (await driver.getText(statusField) == 'ok') { + await driver.tap(stepButton); + step++; + } + final String status = await driver.getText(statusField); + if (status != 'complete') { + fail('Failed at step $step with status $status'); + } + }); + + tearDownAll(() async { + driver?.close(); + }); + }); +}