Skip to content
This repository has been archived by the owner on Jul 1, 2023. It is now read-only.

WIP: iOS support #73

Draft
wants to merge 16 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
179 changes: 179 additions & 0 deletions flutter_wasm/bin/ios_setup.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// Builds the wasmer runtime library for iOS, as a static framework.
// Usage: flutter pub run flutter_wasm:ios_setup path/to/output/directory

import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:path/path.dart' as path;
import 'package:wasm/src/shared.dart';

final thisDir = path.dirname(Platform.script.path);
const inputLibName = 'libwasmer.dylib';
const outputLibName = 'flutter_wasm';
const archiveName = 'flutter_wasm_archive';

class Abi {
final String triple;
Abi(this.triple);
}

class IOSSdk {
final String xcodeName;
final List<Abi> abis;
IOSSdk(this.xcodeName, this.abis);

Future<String> findTool(String tool) async {
return await _xcrun(['--sdk', xcodeName, '--find', tool]);
}

Future<String> findSdk() async {
return await _xcrun(['--sdk', xcodeName, '--show-sdk-path']);
}
}

final List<IOSSdk> iOSSdks = [
/*IOSSdk('iphoneos', [
// Abi('armv7-apple-ios'),
Abi('aarch64-apple-ios'),
]),*/
IOSSdk('iphonesimulator', [
//Abi('aarch64-apple-ios-sim'),
Abi('x86_64-apple-ios'),
]),
];

Future<void> checkResult(Process process) async {
final result = await process.exitCode;
if (result != 0) {
exitCode = result;
throw Exception('Build failed. Scroll up for the logs.');
}
}

Future<void> _run(String program, List<String> args) async {
print('FFFFF: ${Platform.script.path}');
print('$program ${args.join(' ')}');
final process = await Process.start(
program,
args,
workingDirectory: thisDir,
);
unawaited(stderr.addStream(process.stderr));
unawaited(stdout.addStream(process.stdout));
await checkResult(process);
}

void copyDirectory(String from, String to) {
for (final f in Directory(from).listSync(recursive: true)) {
if (f is File) {
final toPath = path.join(to, path.relative(f.path, from: from));
Directory(path.dirname(toPath)).createSync(recursive: true);
f.copySync(toPath);
}
}
}

Future<String> _xcrun(List<String> args) async {
final process = await Process.start(
'xcrun',
args
);
unawaited(stderr.addStream(process.stderr));
final out = await process.stdout
.transform(utf8.decoder)
.transform(LineSplitter())
.firstWhere((line) => line.isNotEmpty);
await checkResult(process);
return out;
}

Future<void> main(List<String> args) async {
await _run('flutter', ['pub', 'get']);

final outDir = Directory(args[0]);
print('Output directory: ${outDir.path}');
print('This directory: $thisDir');

if (!outDir.existsSync()) {
await outDir.create(recursive: true);
}

final tempFrameworks = <String>[];
for (final iOSSdk in iOSSdks) {
final sdkOutDir = path.join(thisDir, 'ios/build/${iOSSdk.xcodeName}');
// final frameworkTemplatePath = path.join(thisDir, 'ios/FrameworkTemplate');

// HACK
final frameworkTemplatePath = '/Users/liama/dev/wasm/flutter_wasm/ios/FrameworkTemplate';
print('zzzzzzz: $frameworkTemplatePath');

final libs = <String>[];
final sdkPath = await iOSSdk.findSdk();
final clangPath = await iOSSdk.findTool('clang');
final clangppPath = await iOSSdk.findTool('clang++');
final lipoPath = await iOSSdk.findTool('lipo');
final arPath = await iOSSdk.findTool('ar');
for (final abi in iOSSdk.abis) {
final abiOutDir = Directory(path.join(sdkOutDir, abi.triple));
print('Building for ${abi.triple} in $abiOutDir');
if (!abiOutDir.existsSync()) {
await abiOutDir.create(recursive: true);
}
// await _run('flutter', [
// 'pub',
// 'run',
// 'wasm:setup',
// '-t',
// abi.triple,
// '-o',
// abiOutDir.path,
// '--clang',
// clangPath,
// '--clangpp',
// clangppPath,
// '--ar',
// arPath,
// '--sysroot',
// sdkPath,
// ]);

// HACK
File('/Users/liama/libwasmer.dylib').copySync('/Users/liama/dev/wasm/flutter_wasm/example/.dart_tool/pub/bin/flutter_wasm/ios/build/iphonesimulator/x86_64-apple-ios/libwasmer.dylib');

libs.add(path.join(abiOutDir.path, inputLibName));
}
final fatLibPath = path.join(sdkOutDir, outputLibName);
print('Creating fat library for ${iOSSdk.xcodeName} at $fatLibPath');
await _run(lipoPath, ['-create', ...libs, '-output', fatLibPath]);
// final archivePath = sdkOutDir.resolve(archiveName).toFilePath();
// await _run(xcodebuildPath, [
// 'archive', '-scheme', 'WhatIsAScheme',
// '-library', fatLibPath,
// '-destination', 'generic/platform=${iOSSdk.xcodeName}',
// '-archivePath', archivePath
// ]);
final tempFrameworkPath = path.join(sdkOutDir, 'lib_wasm.framework');
copyDirectory(frameworkTemplatePath, tempFrameworkPath);
File(fatLibPath).copySync(path.join(tempFrameworkPath, 'lib_wasm'));
tempFrameworks.add(tempFrameworkPath);
}
final frameworkPath =
path.join(outDir.path, 'Frameworks/flutter_wasm.xcframework');
final frameworkDir = Directory(frameworkPath);
if (await frameworkDir.exists()) {
await frameworkDir.delete(recursive: true);
}
print('Creating framework at $frameworkPath');
await _run('xcrun', [
'xcodebuild',
'-create-xcframework',
for (final temp in tempFrameworks) ...['-framework', temp],
'-output',
frameworkPath,
]);
}
34 changes: 34 additions & 0 deletions flutter_wasm/example/ios/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
**/dgph
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*

# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3
26 changes: 26 additions & 0 deletions flutter_wasm/example/ios/Flutter/AppFrameworkInfo.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>9.0</string>
</dict>
</plist>
2 changes: 2 additions & 0 deletions flutter_wasm/example/ios/Flutter/Debug.xcconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
2 changes: 2 additions & 0 deletions flutter_wasm/example/ios/Flutter/Release.xcconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
41 changes: 41 additions & 0 deletions flutter_wasm/example/ios/Podfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}

def flutter_root
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

File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end

require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)

flutter_ios_podfile_setup

target 'Runner' do
use_frameworks!
use_modular_headers!

flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end

post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end
22 changes: 22 additions & 0 deletions flutter_wasm/example/ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
PODS:
- Flutter (1.0.0)
- flutter_wasm (0.0.1):
- Flutter

DEPENDENCIES:
- Flutter (from `Flutter`)
- flutter_wasm (from `.symlinks/plugins/flutter_wasm/ios`)

EXTERNAL SOURCES:
Flutter:
:path: Flutter
flutter_wasm:
:path: ".symlinks/plugins/flutter_wasm/ios"

SPEC CHECKSUMS:
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
flutter_wasm: a16d7dd9ea91bc62f163ba704fe5597905a347ac

PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c

COCOAPODS: 1.11.2
Loading