Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
e8e5de44
Unverified
Commit
e8e5de44
authored
Jul 28, 2020
by
Jenn Magder
Committed by
GitHub
Jul 28, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Parse .flutter-plugins-dependencies for add-to-app iOS modules (#61269)
parent
734782f5
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
90 additions
and
76 deletions
+90
-76
module_test_ios.dart
dev/devicelab/bin/tasks/module_test_ios.dart
+31
-32
ios.dart
dev/devicelab/lib/framework/ios.dart
+7
-2
podhelper.rb.tmpl
...mplates/module/ios/library/Flutter.tmpl/podhelper.rb.tmpl
+52
-42
No files found.
dev/devicelab/bin/tasks/module_test_ios.dart
View file @
e8e5de44
...
...
@@ -14,6 +14,7 @@ import 'package:path/path.dart' as path;
/// adding Flutter to an existing iOS app.
Future
<
void
>
main
()
async
{
await
task
(()
async
{
String
simulatorDeviceId
;
section
(
'Create Flutter module project'
);
final
Directory
tempDir
=
Directory
.
systemTemp
.
createTempSync
(
'flutter_module_test.'
);
...
...
@@ -52,7 +53,7 @@ Future<void> main() async {
);
});
final
Directory
ephemeral
Release
HostApp
=
Directory
(
path
.
join
(
final
Directory
ephemeral
IOS
HostApp
=
Directory
(
path
.
join
(
projectDir
.
path
,
'build'
,
'ios'
,
...
...
@@ -60,13 +61,13 @@ Future<void> main() async {
'Runner.app'
,
));
if
(!
exists
(
ephemeral
Release
HostApp
))
{
if
(!
exists
(
ephemeral
IOS
HostApp
))
{
return
TaskResult
.
failure
(
'Failed to build ephemeral host .app'
);
}
if
(!
await
_isAppAotBuild
(
ephemeral
Release
HostApp
))
{
if
(!
await
_isAppAotBuild
(
ephemeral
IOS
HostApp
))
{
return
TaskResult
.
failure
(
'Ephemeral host app
${ephemeral
Release
HostApp.path}
was not a release build as expected'
'Ephemeral host app
${ephemeral
IOS
HostApp.path}
was not a release build as expected'
);
}
...
...
@@ -85,21 +86,13 @@ Future<void> main() async {
);
});
final
Directory
ephemeralProfileHostApp
=
Directory
(
path
.
join
(
projectDir
.
path
,
'build'
,
'ios'
,
'iphoneos'
,
'Runner.app'
,
));
if
(!
exists
(
ephemeralProfileHostApp
))
{
if
(!
exists
(
ephemeralIOSHostApp
))
{
return
TaskResult
.
failure
(
'Failed to build ephemeral host .app'
);
}
if
(!
await
_isAppAotBuild
(
ephemeral
Profile
HostApp
))
{
if
(!
await
_isAppAotBuild
(
ephemeral
IOS
HostApp
))
{
return
TaskResult
.
failure
(
'Ephemeral host app
${ephemeral
Profile
HostApp.path}
was not a profile build as expected'
'Ephemeral host app
${ephemeral
IOS
HostApp.path}
was not a profile build as expected'
);
}
...
...
@@ -118,7 +111,7 @@ Future<void> main() async {
);
});
final
Directory
ephemeral
Debug
HostApp
=
Directory
(
path
.
join
(
final
Directory
ephemeral
Simulator
HostApp
=
Directory
(
path
.
join
(
projectDir
.
path
,
'build'
,
'ios'
,
...
...
@@ -126,19 +119,19 @@ Future<void> main() async {
'Runner.app'
,
));
if
(!
exists
(
ephemeral
Debug
HostApp
))
{
if
(!
exists
(
ephemeral
Simulator
HostApp
))
{
return
TaskResult
.
failure
(
'Failed to build ephemeral host .app'
);
}
if
(!
exists
(
File
(
path
.
join
(
ephemeral
Debug
HostApp
.
path
,
ephemeral
Simulator
HostApp
.
path
,
'Frameworks'
,
'App.framework'
,
'flutter_assets'
,
'isolate_snapshot_data'
,
))))
{
return
TaskResult
.
failure
(
'Ephemeral host app
${ephemeral
Debug
HostApp.path}
was not a debug build as expected'
'Ephemeral host app
${ephemeral
Simulator
HostApp.path}
was not a debug build as expected'
);
}
...
...
@@ -154,7 +147,8 @@ Future<void> main() async {
String
content
=
await
pubspec
.
readAsString
();
content
=
content
.
replaceFirst
(
'
\n
dependencies:
\n
'
,
'
\n
dependencies:
\n
device_info:
\n
google_maps_flutter:
\n
'
,
// One dynamic and one static framework.
// One dynamic framework, one static framework, and one that does not support iOS.
'
\n
dependencies:
\n
device_info:
\n
google_maps_flutter:
\n
android_alarm_manager:
\n
'
,
);
await
pubspec
.
writeAsString
(
content
,
flush:
true
);
await
inDirectory
(
projectDir
,
()
async
{
...
...
@@ -173,13 +167,7 @@ Future<void> main() async {
);
});
final
bool
ephemeralHostAppWithCocoaPodsBuilt
=
exists
(
Directory
(
path
.
join
(
projectDir
.
path
,
'build'
,
'ios'
,
'iphoneos'
,
'Runner.app'
,
)));
final
bool
ephemeralHostAppWithCocoaPodsBuilt
=
exists
(
ephemeralIOSHostApp
);
if
(!
ephemeralHostAppWithCocoaPodsBuilt
)
{
return
TaskResult
.
failure
(
'Failed to build ephemeral host .app with CocoaPods'
);
...
...
@@ -190,10 +178,19 @@ Future<void> main() async {
if
(!
podfileLockOutput
.
contains
(
':path: Flutter/engine'
)
||
!
podfileLockOutput
.
contains
(
':path: Flutter/FlutterPluginRegistrant'
)
||
!
podfileLockOutput
.
contains
(
':path: Flutter/.symlinks/device_info/ios'
)
||
!
podfileLockOutput
.
contains
(
':path: Flutter/.symlinks/google_maps_flutter/ios'
))
{
||
!
podfileLockOutput
.
contains
(
':path: Flutter/.symlinks/google_maps_flutter/ios'
)
||
podfileLockOutput
.
contains
(
'android_alarm_manager'
))
{
return
TaskResult
.
failure
(
'Building ephemeral host app Podfile.lock does not contain expected pods'
);
}
checkFileExists
(
path
.
join
(
ephemeralIOSHostApp
.
path
,
'Frameworks'
,
'device_info.framework'
,
'device_info'
));
// Static, no embedded framework.
checkDirectoryNotExists
(
path
.
join
(
ephemeralIOSHostApp
.
path
,
'Frameworks'
,
'google_maps_flutter.framework'
));
// Android-only, no embedded framework.
checkDirectoryNotExists
(
path
.
join
(
ephemeralIOSHostApp
.
path
,
'Frameworks'
,
'android_alarm_manager.framework'
));
section
(
'Add to existing iOS Objective-C app'
);
final
Directory
objectiveCHostApp
=
Directory
(
path
.
join
(
tempDir
.
path
,
'hello_host_app'
));
...
...
@@ -255,8 +252,9 @@ Future<void> main() async {
}
section
(
'Run platform unit tests'
);
await
testWithNewiOSSimulator
(
'TestAdd2AppSim'
,
(
String
deviceId
)
=>
inDirectory
(
objectiveCHostApp
,
()
=>
await
testWithNewIOSSimulator
(
'TestAdd2AppSim'
,
(
String
deviceId
)
{
simulatorDeviceId
=
deviceId
;
return
inDirectory
(
objectiveCHostApp
,
()
=>
exec
(
'xcodebuild'
,
<
String
>[
...
...
@@ -275,8 +273,8 @@ Future<void> main() async {
'EXPANDED_CODE_SIGN_IDENTITY=-'
,
'COMPILER_INDEX_STORE_ENABLE=NO'
,
],
)
)
)
);
}
);
section
(
'Fail building existing Objective-C iOS app if flutter script fails'
);
...
...
@@ -371,6 +369,7 @@ Future<void> main() async {
}
catch
(
e
)
{
return
TaskResult
.
failure
(
e
.
toString
());
}
finally
{
removeIOSimulator
(
simulatorDeviceId
);
rmTree
(
tempDir
);
}
});
...
...
dev/devicelab/lib/framework/ios.dart
View file @
e8e5de44
...
...
@@ -103,8 +103,10 @@ Future<bool> containsBitcode(String pathToBinary) async {
}
/// Creates and boots a new simulator, passes the new simulator's identifier to
/// `testFunction`, then shuts down and deletes simulator.
Future
<
void
>
testWithNewiOSSimulator
(
/// `testFunction`.
///
/// Remember to call removeIOSimulator in the test teardown.
Future
<
void
>
testWithNewIOSSimulator
(
String
deviceName
,
SimulatorFunction
testFunction
,
{
String
deviceTypeId
=
'com.apple.CoreSimulator.SimDeviceType.iPhone-11'
,
...
...
@@ -160,7 +162,10 @@ Future<void> testWithNewiOSSimulator(
);
await
testFunction
(
deviceId
);
}
/// Shuts down and deletes simulator with deviceId.
Future
<
void
>
removeIOSimulator
(
String
deviceId
)
async
{
if
(
deviceId
!=
null
&&
deviceId
!=
''
)
{
await
eval
(
'xcrun'
,
...
...
packages/flutter_tools/templates/module/ios/library/Flutter.tmpl/podhelper.rb.tmpl
View file @
e8e5de44
# Copyright 2014 The Flutter Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
require 'json'
# Install pods needed to embed Flutter application, Flutter engine, and plugins
# from the host application Podfile.
#
...
...
@@ -22,7 +28,8 @@ end
# install_flutter_engine_pod
# end
def install_flutter_engine_pod
engine_dir = File.join(__dir__, 'engine')
current_directory = File.expand_path('..', __FILE__)
engine_dir = File.expand_path('engine', current_directory)
if !File.exist?(engine_dir)
# Copy the debug engine to have something to link against if the xcode backend script has not run yet.
# CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist.
...
...
@@ -35,7 +42,8 @@ def install_flutter_engine_pod
# Keep pod path relative so it can be checked into Podfile.lock.
# Process will be run from project directory.
engine_pathname = Pathname.new engine_dir
project_directory_pathname = Pathname.new Dir.pwd
# defined_in_file is set by CocoaPods and is a Pathname to the Podfile.
project_directory_pathname = defined_in_file.dirname
relative = engine_pathname.relative_path_from project_directory_pathname
pod 'Flutter', :path => relative.to_s, :inhibit_warnings => true
...
...
@@ -55,19 +63,26 @@ def install_flutter_plugin_pods(flutter_application_path)
# Keep pod path relative so it can be checked into Podfile.lock.
# Process will be run from project directory.
current_directory_pathname = Pathname.new __dir__
project_directory_pathname = Pathname.new Dir.pwd
current_directory_pathname = Pathname.new File.expand_path('..', __FILE__)
# defined_in_file is set by CocoaPods and is a Pathname to the Podfile.
project_directory_pathname = defined_in_file.dirname
relative = current_directory_pathname.relative_path_from project_directory_pathname
pod 'FlutterPluginRegistrant', :path => File.join(relative, 'FlutterPluginRegistrant'), :inhibit_warnings => true
symlinks_dir = File.join(relative, '.symlinks')
FileUtils.mkdir_p(symlinks_dir)
plugin_pods = parse_KV_file(File.join(flutter_application_path, '.flutter-plugins'))
plugin_pods.map do |r|
symlink = File.join(symlinks_dir, r[:name])
FileUtils.rm_f(symlink)
File.symlink(r[:path], symlink)
pod r[:name], :path => File.join(symlink, 'ios'), :inhibit_warnings => true
plugins_file = File.expand_path('.flutter-plugins-dependencies', flutter_application_path)
plugin_pods = flutter_parse_dependencies_file_for_ios_plugin(plugins_file)
plugin_pods.each do |plugin_hash|
plugin_name = plugin_hash['name']
plugin_path = plugin_hash['path']
if (plugin_name && plugin_path)
symlink = File.join(symlinks_dir, plugin_name)
FileUtils.rm_f(symlink)
File.symlink(plugin_path, symlink)
pod plugin_name, :path => File.join(symlink, 'ios'), :inhibit_warnings => true
end
end
end
...
...
@@ -81,7 +96,7 @@ end
# Optional, defaults to two levels up from the directory of this script.
# MyApp/my_flutter/.ios/Flutter/../..
def install_flutter_application_pod(flutter_application_path)
app_framework_dir = File.
join(__dir__, 'App.framework'
)
app_framework_dir = File.
expand_path('App.framework', File.join('..', __FILE__)
)
app_framework_dylib = File.join(app_framework_dir, 'App')
if !File.exist?(app_framework_dylib)
# Fake an App.framework to have something to link against if the xcode backend script has not run yet.
...
...
@@ -93,8 +108,9 @@ def install_flutter_application_pod(flutter_application_path)
# Keep pod and script phase paths relative so they can be checked into source control.
# Process will be run from project directory.
current_directory_pathname = Pathname.new __dir__
project_directory_pathname = Pathname.new Dir.pwd
current_directory_pathname = Pathname.new File.expand_path('..', __FILE__)
# defined_in_file is set by CocoaPods and is a Pathname to the Podfile.
project_directory_pathname = defined_in_file.dirname
relative = current_directory_pathname.relative_path_from project_directory_pathname
pod '{{projectName}}', :path => relative.to_s, :inhibit_warnings => true
...
...
@@ -110,37 +126,31 @@ def install_flutter_application_pod(flutter_application_path)
:execution_position => :before_compile
end
def parse_KV_file(file, separator='=')
file_abs_path = File.expand_path(file)
if !File.exists? file_abs_path
return [];
end
pods_array = []
skip_line_start_symbols = ["#", "/"]
File.foreach(file_abs_path) { |line|
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
plugin = line.split(pattern=separator)
if plugin.length == 2
podname = plugin[0].strip()
path = plugin[1].strip()
podpath = File.expand_path("#{path}", file_abs_path)
pods_array.push({:name => podname, :path => podpath});
else
puts "Invalid plugin specification: #{line}"
end
}
return pods_array
# .flutter-plugins-dependencies format documented at
# https://flutter.dev/go/plugins-list-migration
def flutter_parse_dependencies_file_for_ios_plugin(file)
file_path = File.expand_path(file)
return [] unless File.exists? file_path
dependencies_file = File.read(file)
dependencies_hash = JSON.parse(dependencies_file)
# dependencies_hash.dig('plugins', 'ios') not available until Ruby 2.3
return [] unless dependencies_hash.has_key?('plugins')
return [] unless dependencies_hash['plugins'].has_key?('ios')
dependencies_hash['plugins']['ios'] || []
end
def flutter_root
generated_xcode_build_settings = parse_KV_file(File.join(__dir__, 'Generated.xcconfig'))
if generated_xcode_build_settings.empty?
puts "Generated.xcconfig must exist. Make sure `flutter pub get` is executed in the Flutter module."
exit
generated_xcode_build_settings_path = File.expand_path(File.join('..', '..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
generated_xcode_build_settings.map { |p|
if p[:name] == 'FLUTTER_ROOT'
return p[:path]
end
}
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
# This should never happen...
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment