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