The articles
Look for similar pictures in IOS album NSNotification and class object, instance object icloud-Documents storage CocoaPods private source build Swarm blockchain distributed storage using MacOS stream editor sed
Create the Flutter module
Template generation project
First, switch to a directory where the Flutter module is stored. Create a template project using the command flutter create –template module moduleName
cd some/path/
flutter create --template module moduleName
Copy the code
ModuleName is the name of our generated module.
This command has successfully created a my_flutter template project
Formwork construction
After the template project is created, let’s look at the structure of the template project.
As you can see, the Structure of the Flutter module directory is similar to that of the Project Directory. The functions of each directory are as follows
directory | role |
---|---|
.android | Store android Project directory (for running the shell project of the Flutter module alone) |
.ios | Store the ios project directory (for running the Shell project of the Flutter module alone) |
lib | Storing the source code of Flutter |
pubspec.yaml | Flutter profile |
.ios directory and ios directory
As you can see from the template structure, there are no Android and ios directories. Just the.ios and.Android directories. So. what’s the difference between the ios directory and the ios directory?
. Ios directory structure
Ios directory structure
In Project Flutter, the ios directory is a repository of project Flutter products compiled for the ios platform and used to publish the Flutter app (on ios) or to use specific functions in XCode (e.g. enable push, icloud container, location, permissions, etc.)
In the Flutter module project, the.ios directory is a shell project for running your Flutter module alone. For example, if you don’t want to rebuild the entire original project, you can use this shell project to run and test your Flutter module.
In addition, the. Ios directory contains the App.framework, which contains the compilation of the Dart source code from our Flutter module
The FlutterPluginRegistrant directory is used to hold our flutter third party plug-ins
There is also the Engin directory for running our Flutter module in the ios environment.
And the Flutter module installation help script podhelper.rb
Note that the ios platform code is written in our ios native project, not in the shell project of the Flutter module in the ios directory. The flutter module shell project in the.ios directory may be overwritten by the Flutter and will not be integrated into your existing XCode project. Do not put ios code, do not put ios code, do not put ios code
Install the Flutter module into the Xcode project
CocoaPod installation
Start by creating a Podfile
cd path
vim Podfile
Copy the code
Configure the Podfile contents
flutter_application_path = '/xxxxxxx/my_flutter'
load File.join(flutter_application_path, '.ios'.'Flutter'.'podhelper.rb')
platform :ios.'9.1'
target 'myFlutterModule' do
pod 'Masonry'
install_all_flutter_pods(flutter_application_path)
end
Copy the code
Flutter_application_path indicates the directory path of your Flutter module project. After you have found the Flutter module project, go to the.ios directory and find the installation script podhelper.rb in the.ios directory under the Flutter directory
The script flow for installing the FLUTTER module is shown in the following figure
By looking at the PodHelper script code we can see that it mainly packages three directories in.ios
def install_flutter_engine_pod
current_directory = File.expand_path('.. '.__FILE__)
engine_dir = File.expand_path('engine', current_directory)
framework_name = 'Flutter.xcframework'
copied_engine = File.expand_path(framework_name, engine_dir)
if! File.exist? (copied_engine)# 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.
release_framework_dir = File.join(flutter_root, 'bin'.'cache'.'artifacts'.'engine'.'ios-release')
unlessDir.exist? (release_framework_dir)# iOS artifacts have not been downloaded.
raise "#{release_framework_dir} must exist. Make sure \"flutter build ios\" has been run at least once"
end
FileUtils.cp_r(File.join(release_framework_dir, framework_name), engine_dir)
end
# 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
# 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
end
Copy the code
This method is used to package the Flutter. Xcframework in the engine directory mentioned above, which is the engine on which our Flutter runs
def install_flutter_plugin_pods(flutter_application_path)
flutter_application_path ||= File.join('.. '.'.. ')
# Keep pod path relative so it can be checked into Podfile.lock.
# Process will be run from project directory.
ios_project_directory_pathname = Pathname.new File.expand_path(File.join('.. '.'.. '), __FILE__)
# defined_in_file is set by CocoaPods and is a Pathname to the Podfile.
project_directory_pathname = defined_in_file.dirname
relative = ios_project_directory_pathname.relative_path_from project_directory_pathname
pod 'FlutterPluginRegistrant'.:path => File.join(relative, 'Flutter'.'FlutterPluginRegistrant'), :inhibit_warnings= >true
symlinks_dir = File.join(relative, '.symlinks'.'plugins')
FileUtils.mkdir_p(symlinks_dir)
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
Copy the code
This method is used to package the FlutterPluginRegistrant directory, which holds the third-party plug-ins we use in the Flutter module
def install_flutter_application_pod(flutter_application_path)
current_directory_pathname = Pathname.new File.expand_path('.. '.__FILE__)
app_framework_dir = File.expand_path('App.framework', current_directory_pathname.to_path)
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.
# CocoaPods will not embed the framework on pod install (before any build phases can run) if the dylib does not exist.
# Create a dummy dylib.
FileUtils.mkdir_p(app_framework_dir)
`echo "static const int Moo = 88;" | xcrun clang -x c -dynamiclib -o "#{app_framework_dylib}" -`
end
# Keep pod and script phase paths relative so they can be checked into source control.
# Process will be run from project directory.
# 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 'my_flutter'.:path => relative.to_s, :inhibit_warnings= >true
flutter_export_environment_path = File.join('${SRCROOT}', relative, 'flutter_export_environment.sh');
script_phase :name= >'Run Flutter Build my_flutter Script'.:script= >"set -e\nset -u\nsource \"#{flutter_export_environment_path}\"\nexport VERBOSE_SCRIPT_LOGGING=1 && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/xcode_backend.sh build".:execution_position= >:before_compile
end
Copy the code
This method is used to package the results of the compilation of the Flutter module source code
Then run Pod Install to add the Flutter module to our project.
Note here that the target of a Pod corresponds to an install_ALL_Flutter_Pods. In this example we only import Install_all_Flutter_Pods into the myFlutterModule target. If there are other targets that need to use the Flutter module, You need to import install_ALL_Flutter_Pods under the target.
After Pod Intall completes, we see that three modules have been successfully installed
In the project generated by CocoaPod, we have access to each of the three modules to compile the product for the Flutter module source, the flutter running engine, and the plugin used by the flutter module
Open our project in Xcode and you can now use the ⌘B compilation project.
Pay attention to
When we changed the plugins that the Flutter module depended on in pubspec. Yaml, we needed to update the list of plugins that would be used by the Podhelper.rb script using the Flutter pub get in the Flutter module directory. Then use Pod Install again in our Xcode project
In addition, the changes in the Lib source file of the Flutter module are automatically updated through the script every time Xcode builds an IOS project. So we don’t need to re-install Pod using Pod Install, change the module style or functionality directly in the Flutter module, and then build the project directly in Xcode.
Invoke the Flutter page on IOS projects
AppDelegate set
Here recommend let our AppDelegate inherit FlutterAppDelegate directly, or you can choose not to inherit, if no inheritance, you need to achieve in the AppDelegate FlutterAppLifeCycleProvider agreement, To ensure that the Flutter plugins receive the necessary callbacks
For convenience, WHAT I’ve chosen here is to have the AppDelegate inherit from FlutterAppDelegate
AppDelegate. H file
@import UIKit;
@import Flutter;
@interface AppDelegate : FlutterAppDelegate
@property (nonatomic.strong) FlutterEngine *flutterEngine;
@end
Copy the code
AppDelegate. M file
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.flutterEngine = [[FlutterEngine alloc] initWithName:@"coderjun flutter engine"];
// Runs the default Dart entrypoint with a default Flutter route.
[self.flutterEngine run];
// Used to connect plugins (only if you have plugins with iOS platform code).
[GeneratedPluginRegistrant registerWithRegistry:self.flutterEngine];
return [super application:application didFinishLaunchingWithOptions:launchOptions];;
}
Copy the code
Now I have created our own flutter engine in the AppDelegate.
Now we can use the Flutter engine to run our Flutter module in the ios environment
Use FlutterEngin to display FlutterViewController
Here we simply create a ViewController and switch that ViewController to FlutterViewController
- (void)viewDidLoad {
UIButton* btn = [UIButton buttonWithType:UIButtonTypeContactAdd];
btn.center = self.view.center;
[btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void) btnClick:(UIButton*) sender{
NSLog(@"tag is %ld", (long)index);
FlutterEngine *flutterEngine =
((AppDelegate *)UIApplication.sharedApplication.delegate).flutterEngine;
FlutterViewController *flutterViewController =
[[FlutterViewController alloc] initWithEngine:flutterEngine nibName:nil bundle:nil];
[self presentViewController:flutterViewController animated:YES completion:nil];
}
Copy the code
When we click the button, the ViewController pushes our FlutterViewControler over the current window using a modal view. Results the following
At the end
If there are any mistakes or questions, please leave them in the comments section and I will reply.
My GitHub home page GitHub
Will not regularly do some open source projects for everyone to exchange learning