Set up Flutter for iOS apps
When testing your Flutter application with Perfecto, the following assumptions apply:
-
You build your own application based on the iOS Device Testing instructions.
-
Running the Perfecto Gradle Plugin is best done outside of the source code folder. The application can reside in the cloud, in Git/NAS, and so on.
-
Running the Perfecto Gradle Plugin requires Gradle.
-
You reference the
build.gradle
file and the JSON config file through CLI params. The example in this article implies both files reside in the same directory. If they reside in different directories, some changes in the configuration are required.
Watch this video to see a demo of the Perfecto-Flutter integration setup for iOS. Detailed steps follow.
On this page:
Prerequisites
Before you get started, make sure you have installed the following:
- Gradle
- Java
- Flutter
-
Gradle plugin
You can download the Gradle Plugin either automatically, after adding the required lines of code to the
build.gradle
file, as described in step 2 below, or, if your organization does not permit direct download, by pre-downloading it to a locallibs
folder (see also Install the Perfecto Gradle plugin manually). -
A cloud device with iOS 14 or later
1 | Get started
To get started, you need to create an .ipa
file following the iOS Device Testing instructions.
Flutter uses the 'hosted test module' XCTest architecture, which involves the application .ipa
file that includes the integration tests.
In this step, you prepare this file.
To create the file and convert it to an .ipa file:
-
In Apple Xcode, change the scheme destination to Generic iOS device.
-
Click Product > Build For > Testing. When this is complete, open up the Organizer and select the latest version.
-
Right-click the generated .app file in the Project Navigator (in the Products folder) and select Show in Finder.
Finder displays the path to the Products folder and shows the
Runner.app
package. -
To automatically convert the
.app
files to an.ipa
file, supply the path to the appPath configuration parameters. The Gradle plugin will convert it to an.ipa
file.Alternatively, you can also convert each file manually, as follows:
-
Create an empty Payload (case sensitive) folder and copy the
.app
bundle to this folder.If the Payload folder already exists, delete it and create a new, empty folder.
- Right-click the Payload folder and compress it to a
.zip
file. - Rename the
.zip
file to<testName>.ipa
.
-
When you have the .ipa
file, you can upload it to the Perfecto Repository or keep it on your local machine. Both scenarios will be covered in the following steps.
2 | Configure the Perfecto client environment
In this step, we prepare the following files:
-
A build.gradle file that specifies the required Perfecto dependencies
-
A JSON configuration file that holds all Perfecto configurations, including security information, the Perfecto cloud name, Smart Reporting settings, and test data
The following procedure walks you through the configuration. Expand a step to view its content.
In this step, we prepare the build configuration script that defines the project and its tasks. The information here defines the location of the plugin library and the dependency on the plugin to the build.gradle file. Gradle will look to verify that the plugin is installed before performing the task. If you do not have a .gradle
file, create a new one, named build.gradle
, and apply one of the following additions:
-
If you use maven, use the clean example available here:
build.gradle
example (click to view)You can download the example here: build.gradle
Copybuildscript {
repositories {
jcenter()
maven {
url "https://repo1.perfectomobile.com/public/repositories/maven"
}
}
dependencies {
classpath "com.perfectomobile.instrumentedtest.gradleplugin:plugin:+"
}
}
apply plugin: 'com.perfectomobile.instrumentedtest.gradleplugin'
perfectoGradleSettings {
configFileLocation "configFile.json"} -
If you need to use a local repository, download the Perfecto Gradle plugin manually.
build.gradle
example (click to view)Copybuildscript {
repositories {
jcenter()
flatDir {
dirs '/path_to_JAR_file/'
}
}
dependencies {
classpath "com.perfectomobile.instrumentedtest.gradleplugin:plugin:22.5"
}
}
apply plugin: 'com.perfectomobile.instrumentedtest.gradleplugin'
perfectoGradleSettings {
configFileLocation "configFile.json"
}
-
If you use maven, use the clean example available here:
build.gradle
example (click to view)Copybuildscript {
repositories {
jcenter()
maven {
url "https://repo1.perfectomobile.com/public/repositories/maven"
}
}
dependencies {
classpath "com.perfectomobile.instrumentedtest.gradleplugin:plugin:+"
}
}
apply plugin:'com.perfectomobile.instrumentedtest.gradleplugin'
perfectoGradleSettings {
configFileLocation "configFile.json"
} -
If you need to use a local repository, download the Perfecto Gradle plugin manually.
build.gradle
example (click to view)Copybuildscript {
repositories {
jcenter()
flatDir {
dirs "C:/Flutter_iOS/libs/"
}
}
dependencies {
classpath "com.perfectomobile.instrumentedtest.gradleplugin:plugin:22.5"
}
}
apply plugin:'com.perfectomobile.instrumentedtest.gradleplugin'
perfectoGradleSettings {
configFileLocation "configFile.json"
}
In this step, you create the JSON text file that contains all configuration settings. This is the recommended practice. Configurations include the URL of the Perfecto lab, the security token to use, which devices to select, which tags to use, and so on.
-
Create the configuration file (
configFile.json
) as a JSON text file in a known folder. -
Depending on where your
.ipa
file is located, the file should look as follows:Sample JSON file with.ipa
file located in the Perfecto repository (click to view)Copy{
"cloudURL": "<cloud_id>.perfectomobile.com",
"securityToken":"<TOKEN>",
"appPath":"repository://PUBLIC:flutter_xcuitest.ipa",
"hostedTestModuleName":"RunnerTests",
"isHostedTestModule":true,
"devices": [
{"deviceName":"<deviceID>"},
{"deviceName":"<deviceID>"}
],
"shard": false,
"jobName": "Flutter_iOS_Job",
"jobNumber": 1,
"branch": "Flutter_Branch",
"projectName": "My_Flutter_Project",
"projectVersion": "v1.0",
"tags": ["flutter", "gradleplugin"],
"takeScreenshotOnTestFailure": false,
"takeScreenshotOnTestEnd": false,
"takeScreenshotOnTestStep": false,
"runUITests":true,
"runUnitTests":false,
"installationDetails": {
"resign": true
},
"numOfDevices": 2
}Sample JSON file with.ipa
file located on your local machine (click to view)Copy{
"cloudURL": "<cloud_id>.perfectomobile.com",
"securityToken":"<TOKEN>",
"appPath":"/<path>/flutter_testing.ipa",
"hostedTestModuleName":"RunnerTests",
"isHostedTestModule":true,
"devices": [
{"deviceName":"<deviceID>"},
{"deviceName":"<deviceID>"}
],
"shard": false,
"jobName": "Flutter_iOS_Job",
"jobNumber": 1,
"branch": "Flutter_Branch",
"projectName": "My_Flutter_Project",
"projectVersion": "v1.0",
"tags": ["flutter", "gradleplugin"],
"takeScreenshotOnTestFailure": false,
"takeScreenshotOnTestEnd": false,
"takeScreenshotOnTestStep": false,
"runUITests":true,
"runUnitTests":false,
"installationDetails": {
"resign": true
},
"numOfDevices": 2
} -
Add the connection parameters to the configuration file.
Copy"cloudURL": "<your cloud url>",
"securityToken": "<your cloud security token>"where:
-
cloudURL
is the URL of the Perfecto Lab to connect to, for example mobilecloud.perfectomobile.com.-
securityToken
is the tester's personal security token for the Perfecto lab. See also Generate security tokens.Important: For clouds located in regions other than the US, add theitmsServerUrl
parameter, which specifies the URL of the ITMS server. If not specified, the connection by default goes to the UTMS server in the US. To pass a request to another ITMS server, use the valuehttps://itms-au.perfectomobile.com
for Australia orhttps://itms-eu.perfectomobile.com
for Europe.Copy"itmsServerUrl": "<the URL of the ITMS server>"
-
Add the device selection parameters to the configuration file, as shown in the following examples. For details on platform-specific parameters, see iOS configuration parameters for the Gradle Plugin.
If a device has not been explicitly selected (using the deviceName property) or when numOfDevices is used (without explicitly setting platformVersion), the system automatically selects an iOS device in accordance with the minimum iOS version as defined in your application.
For example, add the following to select:
-
Any available iOS device (based on the gradle task):
"devices": [
{}
], -
Specific devices, such as two devices where one is an iOS device of version 14.4 or later (using a regular expression) and one is randomly selected by the Gradle plugin:
"devices": [
{
"platformName":"IOS",
"platformVersion":"^[14]\\.[4-9].*|^[1-9][0-9].*" },
{}
] -
A number of random iOS devices:
Copy"numOfDevices": 20
-
-
Change the reporting parameter settings to apply tags to the execution report. For more information on adding tags, see Tag-driven reports (RTDD workflow).
Copy"tags": ["plugin", "xctest", "demo"],
"projectName": "playground",
"projectVersion": "1.5",
"jobName": "newFeature",
"jobNumber": "45",where:
tags
is the set of tags to associate with the execution.projectName
is the name of the project, for classification.projectVersion
is the version number assigned to the project for this build.jobName
is the CI identification of the build, used for classification of the report in the CI Dashboard.jobNumber
is the CI job number of the build.
-
Add the application parameters to identify where the application files are located.
For our iOS application, these are:
Copy"appPath": "SimpleAppForTesting.ipa",
"isHostedTestModule":true,
"hostedTestModuleName":"flutter_exampleTests",where:
-
appPath
is the path to the.ipa
or.app
file for the application and unit tests. If the parameter links to an.app
file (Xcode output), the plugin first converts this to an.ipa
file before installing it on the device. -
isHostedTestModule
specifies the hosted XCTest module plugin architecture that Flutter uses. -
hostedTestModuleName
is the name of the XCTest plugin (theXcode::XCUITest
target can be found inXcode::Podfile as target 'flutter_exampleTests' do …
).
-
-
Save the configuration file.
-
Create the configuration file (
configFile.json
) as a JSON text file in a known folder. -
Depending on where your
.ipa
file is located, the file should look as follows:Sample JSON file with.ipa
file located in the Perfecto repository (click to view){
"cloudURL": "<cloud-id>.perfectomobile.com",
"securityToken": "<TOKEN>",
"appPath":"repository://PUBLIC:flutter_testing.ipa",
"hostedTestModuleName":"RunnerTests",
"isHostedTestModule":true,
"devices": [
{
"deviceName" : "deviceID"
},
{
"deviceName" : "deviceID"
}
],
"shard": false,
"jobName": "Flutter_iOS_Job",
"jobNumber": 1,
"branch": "Flutter_Branch",
"projectName": "My_Flutter_Project",
"projectVersion": "v1.0",
"tags": ["flutter", "gradleplugin"],
"takeScreenshotOnTestFailure": false,
"takeScreenshotOnTestEnd": false,
"takeScreenshotOnTestStep": false,
"runUITests":true,
"runUnitTests":false,
"installationDetails": {
"resign": true
},
"numOfDevices": 2
}Sample JSON file with.ipa
file located on your local machine (click to view)Copy{
"cloudURL": "<cloud-id>.perfectomobile.com",
"securityToken": "<TOKEN>",
"appPath":"C:/Flutter_iOS/flutter_testing.ipa",
"hostedTestModuleName":"RunnerTests",
"isHostedTestModule":true,
"devices": [
{
"deviceName" : "deviceID"
},
{
"deviceName" : "deviceID"
}
],
"shard": false,
"jobName": "Flutter_iOS_Job",
"jobNumber": 1,
"branch": "Flutter_Branch",
"projectName": "My_Flutter_Project",
"projectVersion": "v1.0",
"tags": ["flutter", "gradleplugin"],
"takeScreenshotOnTestFailure": false,
"takeScreenshotOnTestEnd": false,
"takeScreenshotOnTestStep": false,
"runUITests":true,
"runUnitTests":false,
"installationDetails": {
"resign": true
},
"numOfDevices": 2
} -
Add the connection parameters to the configuration file.
Copy"cloudURL": "<your cloud url>",
"securityToken": "<your cloud security token>"where:
-
cloudURL
is the URL of the Perfecto Lab to connect to, for example mobilecloud.perfectomobile.com.-
securityToken
is the tester's personal security token for the Perfecto lab. See also Generate security tokens.Important: For clouds located in regions other than the US, add theitmsServerUrl
parameter, which specifies the URL of the ITMS server. If not specified, the connection by default goes to the UTMS server in the US. To pass a request to another ITMS server, use the valuehttps://itms-au.perfectomobile.com
for Australia orhttps://itms-eu.perfectomobile.com
for Europe.Copy"itmsServerUrl": "<the URL of the ITMS server>"
-
Add the device selection parameters to the configuration file, as shown in the following examples. For details on platform-specific parameters, see iOS configuration parameters for the Gradle Plugin.
If a device has not been explicitly selected (using the deviceName property) or when numOfDevices is used (without explicitly setting platformVersion), the system automatically selects an iOS device in accordance with the minimum iOS version as defined in your application.
For example, add the following to select:
-
Any available iOS device (based on the gradle task):
"devices": [
{}
], -
Specific devices, such as two devices where one is an iOS device of version 14.4 or later (using a regular expression) and one is randomly selected by the Gradle plugin:
"devices": [
{
"platformName":"IOS",
"platformVersion":"^[14]\\.[4-9].*|^[1-9][0-9].*" },
{}
] -
A number of random iOS devices:
Copy"numOfDevices": 20
-
-
Change the reporting parameter settings to apply tags to the execution report. For more information on adding tags, see Tag-driven reports (RTDD workflow).
Copy"tags": ["plugin", "xctest", "demo"],
"projectName": "playground",
"projectVersion": "1.5",
"jobName": "newFeature",
"jobNumber": "45",where:
tags
is the set of tags to associate with the execution.projectName
is the name of the project, for classification.projectVersion
is the version number assigned to the project for this build.jobName
is the CI identification of the build, used for classification of the report in the CI Dashboard.jobNumber
is the CI job number of the build.
-
Add the application parameters to identify where the application files are located.
For our iOS application, these are:
Copy"appPath": "SimpleAppForTesting.ipa",
"isHostedTestModule":true,
"hostedTestModuleName":"flutter_exampleTests",where:
-
appPath
is the path to the.ipa
or.app
file for the application and unit tests. If the parameter links to an.app
file (Xcode output), the plugin first converts this to an.ipa
file before installing it on the device. -
isHostedTestModule
specifies the hosted XCTest module plugin architecture that Flutter uses. -
hostedTestModuleName
is the name of the XCTest plugin (theXcode::XCUITest
target can be found inXcode::Podfile as target 'flutter_exampleTests' do …
).
-
-
Save the configuration file.
3 | Run the plugin and view the report
In this step, you run the Perfecto Gradle plugin and viewing the test report in Perfecto.
Expand a step to view its content.
-
Open a command-line (terminal) window in the folder where you want to execute the plugin.
-
Execute the plugin using the following command (Mac and Windows).
Here we also supply the full path to the configuration file created in the previous steps. You can add other configuration parameters (except for device selection) to the command as needed.
Copygradle perfecto-xctest -PconfigFileLocation=configFile.json
This will:
- Select the devices as specified in the Device selection parameters of the configuration file (or a random device if no specification is provided).
- Install the
.ipa
file onto the device. - Run the test methods (based on the configuration parameters).
- Send output to the console window.
The command-line parameters can set any of the configuration parameters, except for device selection parameters. For more information, see iOS configuration parameters for the Gradle Plugin.
For information on running the Gradle plugin over a proxy connection, see Proxy connection.
During the execution, the plugin reports on the progress of the execution and the completion of each test method to the command-line window.
At the end of the execution, the command-line window displays a high-level summary report of the completion status for each device. The report includes:
- Resolution of configuration settings: The configuration file used and the list of the configuration settings for the test run
- Progress notifications as the test is configured, installed, and executed, including notifications of the start and completion of:
- Allocating the device
- Resigning the application
- Installing the application and UI runner files
- Executing the test
- Connecting the video recording
- Completion status for each test method on each device
At the end of the summary report, the plugin provides the URL of the single test report (STR) for the execution run.
Sample Perfecto plugin console output (click to view)CopyParsing configuration file: config.json
Parsed configuration file config.json successfully
Configuration:
cloudURL='<<cloud>>.perfectomobile.com'
appName='app'
tags='[]'
failBuildOnFailure='false'
debug='false'
devices='[{"deviceName":"<<device>>","platformName":"IOS","platformVersion":"^[9]\\.[3-9].*|^[1-9][0-9].*","index":1}]'
acquireDeviceRetryNumber='0'
acquireDeviceRetryInterval='30'
preExecution='{"networkEmulationEnabled":false,"vitalsMonitoringEnabled":false,"locationMockEnabled":false,"reboot":false}'
postExecution='PostExecutionDetails{uninstall=false}'
preCleanUp='false'
resign='true'
takeScreenshotOnTestEnd='true'
takeScreenshotOnTestFailure='true'
shard='false'
ipaPath='/Users/admininstrator/Documents/Flutter/flutter_xcuitest.ipa'
isHostedTestModule='true'
hostedTestModuleName='RunnerTests'
runUITests='true'
runUnitTests='false'
testTimeout='0'
takeScreenshotOnTestStep='true'
You can view your test results in real time at:
https://branchtest.reporting.perfectomobile.com/reporting/library?tags[0]=0987fccf-c47a-4e5d-ba8a-1f298b19b8dc
Files uploaded
Acquiring device based on device management info {"deviceName":"00008110-0001249A3A42801E","platformName":"IOS","platformVersion":"^[9]\\.[3-9].*|^[1-9][0-9].*","automationName":"PerfectoMobile"}
> :perfecto-xctest
Device: <<Device ID>> Apple iPhone-13 Pro: Operating on device {"deviceId":"00008110-0001249A3A42801E","osVersion":"15.0.2","screenResolution":"1170*2532","location":"NA-US-BOS","manufacturer":"Apple","model":"iPhone-13 Pro","firmware":"15.0.2","distributor":"MacCam15","selectionCriteria":{"platformVersion":"^[9]\\.[3-9].*|^[1-9][0-9].*","platformName":"IOS","deviceName":"00008110-0001249A3A42801E"},"os":"iOS"} according to device details {"deviceName":"00008110-0001249A3A42801E","platformName":"IOS","platformVersion":"^[9]\\.[3-9].*|^[1-9][0-9].*","automationName":"PerfectoMobile","index":1}
Device: <<Device ID>> Apple iPhone-13 Pro: Resigning application
Device: <<Device ID>> Apple iPhone-13 Pro: Completed resigning application
Device: <<Device ID>> Apple iPhone-13 Pro: Uploading and installing IPAs to device server
Device: <<Device ID>> Apple iPhone-13 Pro: Completed uploading and installing IPAs to device server
Device: <<Device ID>> Apple iPhone-13 Pro: Starting video recording
Device: <<Device ID>> Apple iPhone-13 Pro: Enabling instrumented test mode
Device: <<Device ID>> Apple iPhone-13 Pro: Starting execution of bundle id com.mcaldwell.dev.flutter.testingApp
Device: <<Device ID>> Apple iPhone-13 Pro: TestResult{className: RunnerTests, methodName: testIntegrationTest, status: PASS}
Device: <<Device ID>> Apple iPhone-13 Pro: Disabling instrumented test mode
Device: <<Device ID>> Apple iPhone-13 Pro: Ending test execution
Device: <<Device ID>> Apple iPhone-13 Pro: Stopping video recording
Device: <<Device ID>> Apple iPhone-13 Pro: Closing device
----------------------------------------------------------------------------
TOTAL SUMMARY
FAILED TO RUN ON 0 devices
RAN SUCCESSFULLY ON 1 device
----------------------------------------------------------------------------
DEVICE 1
Status: ENDED
Device:
00008110-0001249A3A42801E Apple iPhone-13 Pro
Results:
1 TOTAL
0 FAILED
1 PASSED
----------------------------------------------------------------------------
View the detailed report at:
https://branchtest.reporting.perfectomobile.com/reporting/library?tags[0]=0987fccf-c47a-4e5d-ba8a-1f298b19b8dc&startExecutionTime[0]=1652257393334&endExecutionTime[0]=1652257594899
Finished flow execution
BUILD SUCCESSFUL in 3m 52s
To access the execution report, copy the report URL from the summary report on your console and open the URL in your browser. For more information on Smart Reporting, see Test analysis with Smart Reporting. For details on the STR, see Single test report (STR).
Proxy connection
If you run the Gradle plugin over a proxy connection, you can supply the proxy information as follows:
-
As Java parameters when activating the plugin. You can use the same Java Proxy parameters also for proxies supporting SSL encryption.
http.proxyHost: The IP address of the proxy
http.proxyPort: The IP port used for the connection
http.proxyUser: The username for connecting to the proxy server
http.proxyPassword: The password for connecting to the proxy server
For example:
Copygradlew perfecto-android-inst -DconfigFileLocation=configFile.json -Dhttp.proxyHost=10.0.0.100 -Dhttp.proxyPort=8800 -Dhttp.proxyUser=someUserName -Dhttp.proxyPassword=somePassword
-
As parameters defined explicitly in the
gradle.properties
file. For example:CopysystemProp.http.proxyHost=<http-proxy-host>
systemProp.http.proxyPort=<http-proxy-port>
systemProp.https.proxyHost=<https-proxy-host>
systemProp.https.proxyPort=<https-proxy-port>