• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Install pods needed to embed Flutter application, Flutter engine, and plugins
2# from the host application Podfile.
3#
4# @example
5#   target 'MyApp' do
6#     install_all_flutter_pods 'my_flutter'
7#   end
8# @param [String] flutter_application_path Path of the root directory of the Flutter module.
9#                                          Optional, defaults to two levels up from the directory of this script.
10#                                          MyApp/my_flutter/.ios/Flutter/../..
11def install_all_flutter_pods(flutter_application_path = nil)
12  flutter_application_path ||= File.join('..', '..')
13  install_flutter_engine_pod
14  install_flutter_plugin_pods(flutter_application_path)
15  install_flutter_application_pod(flutter_application_path)
16end
17
18# Install Flutter engine pod.
19#
20# @example
21#   target 'MyApp' do
22#     install_flutter_engine_pod
23#   end
24def install_flutter_engine_pod
25  engine_dir = File.join(__dir__, 'engine')
26  if !File.exist?(engine_dir)
27    # Copy the debug engine to have something to link against if the xcode backend script has not run yet.
28    # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist.
29    debug_framework_dir = File.join(flutter_root, 'bin', 'cache', 'artifacts', 'engine', 'ios')
30    FileUtils.mkdir_p(engine_dir)
31    FileUtils.cp_r(File.join(debug_framework_dir, 'Flutter.framework'), engine_dir)
32    FileUtils.cp(File.join(debug_framework_dir, 'Flutter.podspec'), engine_dir)
33  end
34
35  # Keep pod path relative so it can be checked into Podfile.lock.
36  # Process will be run from project directory.
37  engine_pathname = Pathname.new engine_dir
38  project_directory_pathname = Pathname.new Dir.pwd
39  relative = engine_pathname.relative_path_from project_directory_pathname
40
41  pod 'Flutter', :path => relative.to_s, :inhibit_warnings => true
42end
43
44# Install Flutter plugin pods.
45#
46# @example
47#   target 'MyApp' do
48#     install_flutter_plugin_pods 'my_flutter'
49#   end
50# @param [String] flutter_application_path Path of the root directory of the Flutter module.
51#                                          Optional, defaults to two levels up from the directory of this script.
52#                                          MyApp/my_flutter/.ios/Flutter/../..
53def install_flutter_plugin_pods(flutter_application_path)
54  flutter_application_path ||= File.join('..', '..')
55
56  # Keep pod path relative so it can be checked into Podfile.lock.
57  # Process will be run from project directory.
58  current_directory_pathname = Pathname.new __dir__
59  project_directory_pathname = Pathname.new Dir.pwd
60  relative = current_directory_pathname.relative_path_from project_directory_pathname
61  pod 'FlutterPluginRegistrant', :path => File.join(relative, 'FlutterPluginRegistrant'), :inhibit_warnings => true
62
63  symlinks_dir = File.join(relative, '.symlinks')
64  FileUtils.mkdir_p(symlinks_dir)
65  plugin_pods = parse_KV_file(File.join(flutter_application_path, '.flutter-plugins'))
66  plugin_pods.map do |r|
67    symlink = File.join(symlinks_dir, r[:name])
68    FileUtils.rm_f(symlink)
69    File.symlink(r[:path], symlink)
70    pod r[:name], :path => File.join(symlink, 'ios'), :inhibit_warnings => true
71  end
72end
73
74# Install Flutter application pod.
75#
76# @example
77#   target 'MyApp' do
78#     install_flutter_application_pod '../flutter_settings_repository'
79#   end
80# @param [String] flutter_application_path Path of the root directory of the Flutter module.
81#                                          Optional, defaults to two levels up from the directory of this script.
82#                                          MyApp/my_flutter/.ios/Flutter/../..
83def install_flutter_application_pod(flutter_application_path)
84  app_framework_dir = File.join(__dir__, 'App.framework')
85  app_framework_dylib = File.join(app_framework_dir, 'App')
86  if !File.exist?(app_framework_dylib)
87    # Fake an App.framework to have something to link against if the xcode backend script has not run yet.
88    # CocoaPods will not embed the framework on pod install (before any build phases can run) if the dylib does not exist.
89    # Create a dummy dylib.
90    FileUtils.mkdir_p(app_framework_dir)
91    `echo "static const int Moo = 88;" | xcrun clang -x c -dynamiclib -o "#{app_framework_dylib}" -`
92  end
93
94  # Keep pod and script phase paths relative so they can be checked into source control.
95  # Process will be run from project directory.
96  current_directory_pathname = Pathname.new __dir__
97  project_directory_pathname = Pathname.new Dir.pwd
98  relative = current_directory_pathname.relative_path_from project_directory_pathname
99  pod '{{projectName}}', :path => relative.to_s, :inhibit_warnings => true
100
101  flutter_export_environment_path = File.join('${SRCROOT}', relative, 'flutter_export_environment.sh');
102  script_phase :name => 'Run Flutter Build Script',
103    :script => "set -e\nset -u\nsource \"#{flutter_export_environment_path}\"\n\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/xcode_backend.sh build",
104    :input_files => [
105      File.join('${SRCROOT}', flutter_application_path, '.metadata'),
106      File.join('${SRCROOT}', relative, 'App.framework', 'App'),
107      File.join('${SRCROOT}', relative, 'engine', 'Flutter.framework', 'Flutter'),
108      flutter_export_environment_path
109    ],
110    :execution_position => :before_compile
111end
112
113def parse_KV_file(file, separator='=')
114  file_abs_path = File.expand_path(file)
115  if !File.exists? file_abs_path
116    return [];
117  end
118  pods_array = []
119  skip_line_start_symbols = ["#", "/"]
120  File.foreach(file_abs_path) { |line|
121    next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
122    plugin = line.split(pattern=separator)
123    if plugin.length == 2
124      podname = plugin[0].strip()
125      path = plugin[1].strip()
126      podpath = File.expand_path("#{path}", file_abs_path)
127      pods_array.push({:name => podname, :path => podpath});
128     else
129      puts "Invalid plugin specification: #{line}"
130    end
131  }
132  return pods_array
133end
134
135def flutter_root
136  generated_xcode_build_settings = parse_KV_file(File.join(__dir__, 'Generated.xcconfig'))
137  if generated_xcode_build_settings.empty?
138    puts "Generated.xcconfig must exist. Make sure `flutter pub get` is executed in the Flutter module."
139    exit
140  end
141  generated_xcode_build_settings.map { |p|
142    if p[:name] == 'FLUTTER_ROOT'
143      return p[:path]
144    end
145  }
146end
147