├── ios ├── Assets │ └── .gitkeep ├── Classes │ ├── FlutterArchivePlugin.swift │ └── SwiftFlutterArchivePlugin.swift ├── .gitignore └── flutter_archive.podspec ├── test └── flutter_archive_test.dart ├── android ├── settings.gradle ├── gradle.properties ├── .gitignore ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── kineapps │ │ └── flutterarchive │ │ └── FlutterArchivePlugin.kt ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── build.gradle ├── example ├── ios │ ├── Runner │ │ ├── Runner-Bridging-Header.h │ │ ├── Assets.xcassets │ │ │ ├── LaunchImage.imageset │ │ │ │ ├── LaunchImage.png │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ ├── README.md │ │ │ │ └── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ │ └── Contents.json │ │ ├── AppDelegate.swift │ │ ├── Base.lproj │ │ │ ├── Main.storyboard │ │ │ └── LaunchScreen.storyboard │ │ └── Info.plist │ ├── Flutter │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ ├── Flutter.podspec │ │ └── AppFrameworkInfo.plist │ ├── Runner.xcodeproj │ │ ├── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ ├── xcshareddata │ │ │ └── xcschemes │ │ │ │ └── Runner.xcscheme │ │ └── project.pbxproj │ └── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── android │ ├── gradle.properties │ ├── app │ │ ├── src │ │ │ ├── main │ │ │ │ ├── res │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── values │ │ │ │ │ │ └── styles.xml │ │ │ │ │ └── drawable │ │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── kotlin │ │ │ │ │ └── com │ │ │ │ │ │ └── kineapps │ │ │ │ │ │ └── flutter_archive_example │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ └── AndroidManifest.xml │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ └── profile │ │ │ │ └── AndroidManifest.xml │ │ └── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ ├── settings.gradle │ └── build.gradle ├── macos │ ├── Runner │ │ ├── Configs │ │ │ ├── Debug.xcconfig │ │ │ ├── Release.xcconfig │ │ │ ├── Warnings.xcconfig │ │ │ └── AppInfo.xcconfig │ │ ├── Assets.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ ├── app_icon_16.png │ │ │ │ ├── app_icon_32.png │ │ │ │ ├── app_icon_64.png │ │ │ │ ├── app_icon_1024.png │ │ │ │ ├── app_icon_128.png │ │ │ │ ├── app_icon_256.png │ │ │ │ ├── app_icon_512.png │ │ │ │ └── Contents.json │ │ ├── AppDelegate.swift │ │ ├── Release.entitlements │ │ ├── DebugProfile.entitlements │ │ ├── MainFlutterWindow.swift │ │ ├── Info.plist │ │ └── Base.lproj │ │ │ └── MainMenu.xib │ ├── .gitignore │ ├── Flutter │ │ ├── Flutter-Debug.xcconfig │ │ ├── Flutter-Release.xcconfig │ │ └── GeneratedPluginRegistrant.swift │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── Runner.xcodeproj │ │ ├── project.xcworkspace │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ │ └── project.pbxproj ├── .metadata ├── test │ └── widget_test.dart ├── README.md ├── .gitignore ├── pubspec.yaml └── lib │ └── main.dart ├── .gitattributes ├── macos ├── Classes │ ├── SwiftFlutterArchivePlugin.swift │ └── FlutterArchivePlugin.swift └── flutter_archive.podspec ├── .metadata ├── LICENSE_THIRD_PARTY ├── .gitignore ├── LICENSE ├── pubspec.yaml ├── README.md ├── CHANGELOG.md └── lib └── flutter_archive.dart /ios/Assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/flutter_archive_test.dart: -------------------------------------------------------------------------------- 1 | void main() {} 2 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'flutter_archive' 2 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /macos/Classes/SwiftFlutterArchivePlugin.swift: -------------------------------------------------------------------------------- 1 | ../../ios/Classes/SwiftFlutterArchivePlugin.swift -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | android.enableJetifier=true 2 | android.useAndroidX=true 3 | org.gradle.jvmargs=-Xmx1536M 4 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx4G 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /example/macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/xcuserdata/ 7 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /example/macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kineapps/flutter_archive/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/com/kineapps/flutter_archive_example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.kineapps.flutter_archive_example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() 6 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip 6 | -------------------------------------------------------------------------------- /ios/Classes/FlutterArchivePlugin.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | 3 | public class FlutterArchivePlugin: NSObject, FlutterPlugin { 4 | public static func register(with registrar: FlutterPluginRegistrar) { 5 | SwiftFlutterArchivePlugin.register(with: registrar); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /example/macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @NSApplicationMain 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /macos/Classes/FlutterArchivePlugin.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | public class FlutterArchivePlugin: NSObject, FlutterPlugin { 5 | public static func register(with registrar: FlutterPluginRegistrar) { 6 | SwiftFlutterArchivePlugin.register(with: registrar); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip 7 | -------------------------------------------------------------------------------- /example/macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 68587a0916366e9512a78df22c44163d041dd5f3 8 | channel: stable 9 | 10 | project_type: plugin 11 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 0b8abb4724aa590dd0f429683339b1e045a1594d 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /example/macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import flutter_archive 9 | 10 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 11 | FlutterArchivePlugin.register(with: registry.registrar(forPlugin: "FlutterArchivePlugin")) 12 | } 13 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /example/macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController.init() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter_test/flutter_test.dart'; 9 | 10 | void main() { 11 | testWidgets('Verify Platform version', (WidgetTester tester) async {}); 12 | } 13 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | /Flutter/flutter_export_environment.sh -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # flutter_archive_example 2 | 3 | Demonstrates how to use the flutter_archive plugin. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = flutter_archive_example 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.kineapps.flutterArchiveExample 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2020 com.kineapps. All rights reserved. 15 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '2.1.0' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:8.7.3' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | tasks.register("clean", Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /example/ios/Flutter/Flutter.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # This podspec is NOT to be published. It is only used as a local source! 3 | # This is a generated file; do not edit or check into version control. 4 | # 5 | 6 | Pod::Spec.new do |s| 7 | s.name = 'Flutter' 8 | s.version = '1.0.0' 9 | s.summary = 'A UI toolkit for beautiful and fast apps.' 10 | s.homepage = 'https://flutter.dev' 11 | s.license = { :type => 'BSD' } 12 | s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } 13 | s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s } 14 | s.ios.deployment_target = '12.0' 15 | # Framework linking is handled by Flutter tooling, not CocoaPods. 16 | # Add a placeholder to satisfy `s.dependency 'Flutter'` plugin podspecs. 17 | s.vendored_frameworks = 'path/to/nothing' 18 | end 19 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /macos/flutter_archive.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint flutter_archive.podspec' to validate before publishing. 4 | # 5 | Pod::Spec.new do |s| 6 | s.name = 'flutter_archive' 7 | s.version = '0.0.1' 8 | s.summary = 'A new flutter plugin project.' 9 | s.description = <<-DESC 10 | A new flutter plugin project. 11 | DESC 12 | s.homepage = 'http://example.com' 13 | s.license = { :file => '../LICENSE' } 14 | s.author = { 'Your Company' => 'email@example.com' } 15 | s.source = { :path => '.' } 16 | s.source_files = 'Classes/**/*' 17 | s.dependency 'FlutterMacOS' 18 | s.dependency 'ZIPFoundation', '0.9.19' 19 | 20 | s.platform = :osx, '10.11' 21 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } 22 | s.swift_version = '5.0' 23 | end 24 | -------------------------------------------------------------------------------- /ios/flutter_archive.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint flutter_archive.podspec` to validate before publishing. 4 | # 5 | Pod::Spec.new do |s| 6 | s.name = 'flutter_archive' 7 | s.version = '0.0.1' 8 | s.summary = 'A new flutter plugin project.' 9 | s.description = <<-DESC 10 | A new flutter plugin project. 11 | DESC 12 | s.homepage = 'http://example.com' 13 | s.license = { :file => '../LICENSE' } 14 | s.author = { 'Your Company' => 'email@example.com' } 15 | s.source = { :path => '.' } 16 | s.source_files = 'Classes/**/*' 17 | s.public_header_files = 'Classes/**/*.h' 18 | s.dependency 'Flutter' 19 | s.dependency 'ZIPFoundation', '0.9.19' 20 | 21 | s.platform = :ios, '12.0' 22 | s.ios.deployment_target = '12.0' 23 | 24 | # Flutter.framework does not contain a i386 slice. 25 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } 26 | s.swift_version = '5.0' 27 | end 28 | -------------------------------------------------------------------------------- /LICENSE_THIRD_PARTY: -------------------------------------------------------------------------------- 1 | https://github.com/weichsel/ZIPFoundation 2 | 3 | MIT License 4 | 5 | Copyright (c) 2017 Thomas Zoechling 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /example/macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | .pub/ 7 | build/ 8 | pubspec.lock 9 | 10 | # Directory created by dartdoc 11 | /doc/api/ 12 | 13 | # IDE 14 | *.iml // IntelliJ 15 | *.ipr // IntelliJ 16 | *.iws // IntelliJ 17 | .idea/ // IntelliJ 18 | .DS_Store // Mac 19 | 20 | # copied from https://github.com/flutter/plugins/blob/master/.gitignore 21 | .DS_Store 22 | .atom/ 23 | .idea/ 24 | .vscode/ 25 | 26 | .packages 27 | .pub/ 28 | .dart_tool/ 29 | pubspec.lock 30 | flutter_export_environment.sh 31 | 32 | examples/all_plugins/pubspec.yaml 33 | 34 | Podfile 35 | Podfile.lock 36 | Pods/ 37 | .symlinks/ 38 | **/Flutter/App.framework/ 39 | **/Flutter/Flutter.framework/ 40 | **/Flutter/Generated.xcconfig 41 | **/Flutter/flutter_assets/ 42 | ServiceDefinitions.json 43 | xcuserdata/ 44 | **/DerivedData/ 45 | 46 | local.properties 47 | keystore.properties 48 | .gradle/ 49 | gradlew 50 | gradlew.bat 51 | gradle-wrapper.jar 52 | .flutter-plugins-dependencies 53 | *.iml 54 | **/ios/Flutter/ephemeral/ 55 | 56 | GeneratedPluginRegistrant.h 57 | GeneratedPluginRegistrant.m 58 | GeneratedPluginRegistrant.java 59 | build/ 60 | .flutter-plugins 61 | 62 | .project 63 | .classpath 64 | .settings 65 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020 KineApps. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following 13 | disclaimer in the documentation and/or other materials provided 14 | with the distribution. 15 | * Neither the name of copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived 17 | from this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | group 'com.kineapps.flutterarchive' 2 | version '1.0-SNAPSHOT' 3 | 4 | buildscript { 5 | ext.kotlin_version = '2.1.0' 6 | ext.coroutinesVersion = "1.7.3" 7 | repositories { 8 | google() 9 | mavenCentral() 10 | } 11 | 12 | dependencies { 13 | classpath 'com.android.tools.build:gradle:8.7.3' 14 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 15 | } 16 | } 17 | 18 | rootProject.allprojects { 19 | repositories { 20 | google() 21 | mavenCentral() 22 | } 23 | } 24 | 25 | apply plugin: 'com.android.library' 26 | apply plugin: 'kotlin-android' 27 | 28 | android { 29 | // Conditional for compatibility with AGP <4.2. 30 | if (project.android.hasProperty("namespace")) { 31 | namespace 'com.kineapps.flutterarchive' 32 | } 33 | 34 | compileSdkVersion 36 35 | 36 | compileOptions { 37 | sourceCompatibility JavaVersion.VERSION_17 38 | targetCompatibility JavaVersion.VERSION_17 39 | } 40 | 41 | kotlinOptions { 42 | jvmTarget = JavaVersion.VERSION_17.toString() 43 | } 44 | 45 | sourceSets { 46 | main.java.srcDirs += 'src/main/kotlin' 47 | } 48 | defaultConfig { 49 | minSdkVersion 19 50 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 51 | } 52 | lintOptions { 53 | disable 'InvalidPackage' 54 | } 55 | } 56 | 57 | dependencies { 58 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion" 59 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion" 60 | } 61 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | .vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .packages 28 | .pub-cache/ 29 | .pub/ 30 | /build/ 31 | 32 | # Android related 33 | **/android/**/gradle-wrapper.jar 34 | **/android/.gradle 35 | **/android/captures/ 36 | **/android/gradlew 37 | **/android/gradlew.bat 38 | **/android/local.properties 39 | **/android/**/GeneratedPluginRegistrant.java 40 | 41 | # iOS/XCode related 42 | **/ios/**/*.mode1v3 43 | **/ios/**/*.mode2v3 44 | **/ios/**/*.moved-aside 45 | **/ios/**/*.pbxuser 46 | **/ios/**/*.perspectivev3 47 | **/ios/**/*sync/ 48 | **/ios/**/.sconsign.dblite 49 | **/ios/**/.tags* 50 | **/ios/**/.vagrant/ 51 | **/ios/**/DerivedData/ 52 | **/ios/**/Icon? 53 | **/ios/**/Pods/ 54 | **/ios/**/.symlinks/ 55 | **/ios/**/profile 56 | **/ios/**/xcuserdata 57 | **/ios/.generated/ 58 | **/ios/Flutter/App.framework 59 | **/ios/Flutter/Flutter.framework 60 | **/ios/Flutter/Generated.xcconfig 61 | **/ios/Flutter/app.flx 62 | **/ios/Flutter/app.zip 63 | **/ios/Flutter/flutter_assets/ 64 | **/ios/Flutter/flutter_export_environment.sh 65 | **/ios/ServiceDefinitions.json 66 | **/ios/Runner/GeneratedPluginRegistrant.* 67 | 68 | # Exceptions to above rules. 69 | !**/ios/**/default.mode1v3 70 | !**/ios/**/default.mode2v3 71 | !**/ios/**/default.pbxuser 72 | !**/ios/**/default.perspectivev3 73 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 74 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | flutter_archive_example 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | CADisableMinimumFrameDurationOnPhone 45 | 46 | UIApplicationSupportsIndirectInputEvents 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_archive_example 2 | description: Demonstrates how to use the flutter_archive plugin. 3 | version: 0.0.1+1 4 | publish_to: "none" 5 | 6 | environment: 7 | sdk: '>=2.12.0 <3.0.0' 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | 13 | # The following adds the Cupertino Icons font to your application. 14 | # Use with the CupertinoIcons class for iOS style icons. 15 | cupertino_icons: ^1.0.2 16 | 17 | dev_dependencies: 18 | flutter_test: 19 | sdk: flutter 20 | 21 | flutter_archive: 22 | path: ../ 23 | 24 | # For information on the generic Dart part of this file, see the 25 | # following page: https://dart.dev/tools/pub/pubspec 26 | 27 | # The following section is specific to Flutter. 28 | flutter: 29 | # The following line ensures that the Material Icons font is 30 | # included with your application, so that you can use the icons in 31 | # the material Icons class. 32 | uses-material-design: true 33 | # To add assets to your application, add an assets section, like this: 34 | # assets: 35 | # - images/a_dot_burr.jpeg 36 | # - images/a_dot_ham.jpeg 37 | # An image asset can refer to one or more resolution-specific "variants", see 38 | # https://flutter.dev/assets-and-images/#resolution-aware. 39 | # For details regarding adding assets from package dependencies, see 40 | # https://flutter.dev/assets-and-images/#from-packages 41 | # To add custom fonts to your application, add a fonts section here, 42 | # in this "flutter" section. Each entry in this list should have a 43 | # "family" key with the font family name, and a "fonts" key with a 44 | # list giving the asset and other descriptors for the font. For 45 | # example: 46 | # fonts: 47 | # - family: Schyler 48 | # fonts: 49 | # - asset: fonts/Schyler-Regular.ttf 50 | # - asset: fonts/Schyler-Italic.ttf 51 | # style: italic 52 | # - family: Trajan Pro 53 | # fonts: 54 | # - asset: fonts/TrajanPro.ttf 55 | # - asset: fonts/TrajanPro_Bold.ttf 56 | # weight: 700 57 | # 58 | # For details regarding fonts from package dependencies, 59 | # see https://flutter.dev/custom-fonts/#from-packages 60 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_archive 2 | description: Create and extract ZIP archive files in Android, iOS and macOS. Zip all files in a directory recursively or a given list of files. 3 | version: 6.0.4 4 | homepage: https://github.com/kineapps/flutter_archive 5 | repository: https://github.com/kineapps/flutter_archive 6 | 7 | environment: 8 | sdk: '>=2.15.0 <4.0.0' 9 | flutter: ">=2.8.0" 10 | 11 | dependencies: 12 | flutter: 13 | sdk: flutter 14 | 15 | dev_dependencies: 16 | flutter_test: 17 | sdk: flutter 18 | 19 | # For information on the generic Dart part of this file, see the 20 | # following page: https://dart.dev/tools/pub/pubspec 21 | 22 | # The following section is specific to Flutter. 23 | flutter: 24 | # This section identifies this Flutter project as a plugin project. 25 | # The 'pluginClass' and Android 'package' identifiers should not ordinarily 26 | # be modified. They are used by the tooling to maintain consistency when 27 | # adding or updating assets for this project. 28 | plugin: 29 | platforms: 30 | android: 31 | package: com.kineapps.flutterarchive 32 | pluginClass: FlutterArchivePlugin 33 | ios: 34 | pluginClass: FlutterArchivePlugin 35 | macos: 36 | pluginClass: FlutterArchivePlugin 37 | # To add assets to your plugin package, add an assets section, like this: 38 | # assets: 39 | # - images/a_dot_burr.jpeg 40 | # - images/a_dot_ham.jpeg 41 | # 42 | # For details regarding assets in packages, see 43 | # https://flutter.dev/assets-and-images/#from-packages 44 | # 45 | # An image asset can refer to one or more resolution-specific "variants", see 46 | # https://flutter.dev/assets-and-images/#resolution-aware. 47 | # To add custom fonts to your plugin package, add a fonts section here, 48 | # in this "flutter" section. Each entry in this list should have a 49 | # "family" key with the font family name, and a "fonts" key with a 50 | # list giving the asset and other descriptors for the font. For 51 | # example: 52 | # fonts: 53 | # - family: Schyler 54 | # fonts: 55 | # - asset: fonts/Schyler-Regular.ttf 56 | # - asset: fonts/Schyler-Italic.ttf 57 | # style: italic 58 | # - family: Trajan Pro 59 | # fonts: 60 | # - asset: fonts/TrajanPro.ttf 61 | # - asset: fonts/TrajanPro_Bold.ttf 62 | # weight: 700 63 | # 64 | # For details regarding fonts in packages, see 65 | # https://flutter.dev/custom-fonts/#from-packages 66 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | namespace 'com.kineapps.flutter_archive_example' 30 | 31 | compileSdkVersion 36 32 | 33 | compileOptions { 34 | sourceCompatibility JavaVersion.VERSION_17 35 | targetCompatibility JavaVersion.VERSION_17 36 | } 37 | 38 | kotlinOptions { 39 | jvmTarget = JavaVersion.VERSION_17.toString() 40 | } 41 | 42 | sourceSets { 43 | main.java.srcDirs += 'src/main/kotlin' 44 | } 45 | 46 | lintOptions { 47 | disable 'InvalidPackage' 48 | } 49 | 50 | defaultConfig { 51 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 52 | applicationId "com.kineapps.flutter_archive_example" 53 | minSdkVersion 19 54 | targetSdkVersion 31 55 | versionCode flutterVersionCode.toInteger() 56 | versionName flutterVersionName 57 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 58 | } 59 | 60 | buildTypes { 61 | release { 62 | // TODO: Add your own signing config for the release build. 63 | // Signing with the debug keys for now, so `flutter run --release` works. 64 | signingConfig signingConfigs.debug 65 | } 66 | } 67 | } 68 | 69 | flutter { 70 | source '../..' 71 | } 72 | 73 | dependencies { 74 | testImplementation 'junit:junit:4.12' 75 | androidTestImplementation 'androidx.test:runner:1.1.1' 76 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' 77 | } 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flutter_archive 2 | 3 | Create and extract ZIP archive files. Uses Android/iOS/macOS platform APIs for high performance and optimal memory usage. 4 | 5 | ## Features 6 | 7 | - Supports Android (API level 16+), iOS 12+ and macOS 10.11+. 8 | - Modern plugin implementation based on Kotlin (Android) and Swift (iOS/macOS). 9 | - Uses background processing to keep UI responsive. 10 | - Zip all files in a directory (optionally recursively). 11 | - Zip a given list of files. 12 | - Unzip an archive file to a given directory. 13 | - Progress reporting. 14 | - Extract and zip files selectively (allows excluding files). 15 | 16 | ## Examples 17 | 18 | ### Create a zip file from a directory 19 | 20 | ```dart 21 | final dataDir = Directory("data_dir_path"); 22 | try { 23 | final zipFile = File("zip_file_path"); 24 | ZipFile.createFromDirectory( 25 | sourceDir: dataDir, zipFile: zipFile, recurseSubDirs: true); 26 | } catch (e) { 27 | print(e); 28 | } 29 | ``` 30 | 31 | ### Create a zip file from a given list of files. 32 | 33 | ```dart 34 | final sourceDir = Directory("source_dir"); 35 | final files = [ 36 | File(sourceDir.path + "file1"), 37 | File(sourceDir.path + "file2") 38 | ]; 39 | final zipFile = File("zip_file_path"); 40 | try { 41 | ZipFile.createFromFiles( 42 | sourceDir: sourceDir, files: files, zipFile: zipFile); 43 | } catch (e) { 44 | print(e); 45 | } 46 | ``` 47 | 48 | ### Extract a ZIP archive 49 | 50 | ```dart 51 | final zipFile = File("zip_file_path"); 52 | final destinationDir = Directory("destination_dir_path"); 53 | try { 54 | ZipFile.extractToDirectory(zipFile: zipFile, destinationDir: destinationDir); 55 | } catch (e) { 56 | print(e); 57 | } 58 | ``` 59 | 60 | ### Get progress info while extracting a zip archive. 61 | 62 | ```dart 63 | final zipFile = File("zip_file_path"); 64 | final destinationDir = Directory("destination_dir_path"); 65 | try { 66 | await ZipFile.extractToDirectory( 67 | zipFile: zipFile, 68 | destinationDir: destinationDir, 69 | onExtracting: (zipEntry, progress) { 70 | print('progress: ${progress.toStringAsFixed(1)}%'); 71 | print('name: ${zipEntry.name}'); 72 | print('isDirectory: ${zipEntry.isDirectory}'); 73 | print( 74 | 'modificationDate: ${zipEntry.modificationDate.toLocal().toIso8601String()}'); 75 | print('uncompressedSize: ${zipEntry.uncompressedSize}'); 76 | print('compressedSize: ${zipEntry.compressedSize}'); 77 | print('compressionMethod: ${zipEntry.compressionMethod}'); 78 | print('crc: ${zipEntry.crc}'); 79 | return ZipFileOperation.includeItem; 80 | }); 81 | } catch (e) { 82 | print(e); 83 | } 84 | ``` 85 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 6.0.4 2 | - [Android] Updated compileSdkVersion to 36, Gradle to 8.14 and Java/Kotlin compatibility to version 17 3 | 4 | ## 6.0.3 5 | - [iOS] Fixed build issue #78 6 | 7 | ## 6.0.2 8 | - [iOS] Upgraded to ZIPFoundation 0.9.19 9 | 10 | ## 6.0.1 11 | - [iOS] Upgraded to ZIPFoundation 0.9.18 (thanks to AliakseiT) 12 | 13 | ## 6.0.0 14 | - [Andfroid] Fix AGP 8.0 compile error 15 | - [Andfroid] Updated gradle version 7.3.1 and Kotlin version 1.7.10 16 | - [Andfroid] Set compileSdkVersion to 33 17 | 18 | ## 5.0.0 19 | 20 | - [iOS] BRAKING CHANGE: minimum iOS version is now iOS 12.0 21 | - [iOS] Upgraded to ZIPFoundation 0.9.13 (thanks to daniel-possienke) 22 | 23 | ## 4.2.2 24 | 25 | - [iOS] fixed: progress never 100% (thanks to Lan-tb) 26 | - [iOS] added charset support (thanks to Lan-tb) 27 | 28 | ## 4.2.1 29 | 30 | - [Android] Fixed build issue related to Result.error 31 | - fixed sdk constraints 32 | 33 | ## 4.2.0 34 | 35 | - [Android] Fixed #25: added parameter zipFileCharset to ZipFile.extractToDirectory for defining the charset to use 36 | 37 | ## 4.1.1 38 | 39 | - Fixed #43 40 | 41 | ## 4.1.0 42 | 43 | - fixed: skipping file in ZipFile.extractToDirectory did not work 44 | - [Android] updated to Kotlin 1.5.30 45 | - [Android] upgraded gradle 46 | - [Android] jcenter => mavenCentral 47 | - [Android] set compileSdkVersion to 31 48 | - [Android] Removed V1 embedding 49 | - [Android] Fixed warning "inappropriate blocking method call" 50 | - [iOS] updated podspec (added s.swift_version etc.) 51 | 52 | ## 4.0.1 53 | 54 | [iOS] ZipFile.createFromDirectory: fixed issues with file paths 55 | 56 | ## 4.0.0 57 | 58 | - ZipFile.createFromDirectory: added a new parameter onZipping for progress reporting and to allow filtering files to be included in the zip (#30) 59 | - BREAKING CHANGE: replaced enum ExtractOperation with ZipFileOperation 60 | - [iOS] fixed: recurseSubDirs parameter in ZipFile.createFromDirectory was ignored 61 | - [Android] Updated compileSdkVersion and targetSdkVersion to 30 62 | 63 | ## 3.0.0 64 | 65 | - null safety 66 | 67 | ## 2.0.2 68 | 69 | - Fixed minor lint issues 70 | - Experimental fix to #26 (publish plugin from Mac) 71 | 72 | ## 2.0.1 73 | 74 | - Added support for iOS 9 75 | 76 | ## 2.0.0 77 | 78 | - Added support for macOS (thanks for the PR to [tonycn](https://github.com/tonycn)) 79 | 80 | ## 1.0.3 81 | 82 | - Fixed #13: Extracting multiple zip files in parallel does not work when using onExtracting callback 83 | 84 | ## 1.0.2 85 | 86 | - [Android] Fixed: java.lang.ClassCastException: java.util.zip.ZipFile 87 | cannot be cast to java.io.Closeable occurring if API level < 19 88 | 89 | ## 1.0.1 90 | 91 | - Fixed "MissingPluginException" 92 | 93 | ## 1.0.0 94 | 95 | - Renamed FlutterArchive as ZipFile, renamed also methods 96 | - Support for progress reporting in unzip (ZipFile.extractToDirectory) 97 | - Added support for including base directory name to file paths 98 | - [iOS] Upgraded to ZIPFoundation 0.9.11 99 | 100 | ## 0.1.4 101 | 102 | - [Android] Fixed: unzipping some files could fail to "java.util.zip.ZipException: invalid stored block lengths" 103 | - [Android] Fixed: any thrown exception during zip/unzip caused crash 104 | 105 | ## 0.1.3 106 | 107 | - [Android] Improved error handling. 108 | 109 | ## 0.1.2 110 | 111 | - [iOS] Zip/unzip files in a background thread to keep UI more responsive. 112 | 113 | ## 0.1.1+1 114 | 115 | - Minor cleanup. 116 | 117 | ## 0.1.1 118 | 119 | - Added support for Android V2 embedding. 120 | 121 | ## 0.1.0 122 | 123 | - Updated public API. 124 | - Improved documentation. 125 | - Added code samples. 126 | 127 | ## 0.0.2 128 | 129 | - Documented public APIs and updated README.md. 130 | 131 | ## 0.0.1 132 | 133 | - Initial release. 134 | -------------------------------------------------------------------------------- /example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /lib/flutter_archive.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 KineApps. All rights reserved. 2 | // 3 | // This source code is licensed under the BSD-style license found in the 4 | // LICENSE file in the root directory of this source tree. 5 | 6 | import 'dart:async'; 7 | import 'dart:io'; 8 | 9 | import 'package:flutter/services.dart'; 10 | 11 | enum ZipFileOperation { includeItem, skipItem, cancel } 12 | 13 | typedef OnExtracting = ZipFileOperation Function( 14 | ZipEntry zipEntry, double progress); 15 | 16 | typedef OnZipping = ZipFileOperation Function( 17 | String filePath, bool isDirectory, double progress); 18 | 19 | /// Charsets for [ZipFile.extractToDirectory]. 20 | /// https://developer.android.com/reference/java/nio/charset/StandardCharsets 21 | enum Charsets { 22 | // ISO Latin Alphabet No. 23 | ISO_8859_1, 24 | 25 | // Seven-bit ASCII, a.k.a. 26 | US_ASCII, 27 | 28 | // Sixteen-bit UCS Transformation Format, byte order identified by an 29 | // optional byte-order mark 30 | UTF_16, 31 | 32 | // Sixteen-bit UCS Transformation Format, big-endian byte order 33 | UTF_16BE, 34 | 35 | // Sixteen-bit UCS Transformation Format, little-endian byte order 36 | UTF_16LE, 37 | 38 | // Eight-bit UCS Transformation Format 39 | UTF_8, 40 | 41 | // https://en.wikipedia.org/wiki/Code_page_437 42 | CP437, 43 | } 44 | 45 | /// Utility class for creating and extracting zip archive files. 46 | class ZipFile { 47 | static const MethodChannel _channel = MethodChannel('flutter_archive'); 48 | 49 | /// Compress and save all files in [sourceDir] to [zipFile]. 50 | /// 51 | /// Set [includeBaseDirectory] to true to include the directory name from 52 | /// [sourceDir] at the root of the archive. Set [includeBaseDirectory] to 53 | /// false to include only the contents of the [sourceDir]. 54 | /// 55 | /// By default zip all subdirectories recursively. Set [recurseSubDirs] 56 | /// to false to disable recursive zipping. 57 | /// 58 | /// Optional callback function [onZipping] is called before zipping a file 59 | /// or a directory. [onZipping] must return one of the following values: 60 | /// [ZipFileOperation.includeItem] - include this file/directory in zip 61 | /// [ZipFileOperation.skipItem] - exclude this file or directory from the zip 62 | /// [ZipFileOperation.cancel] - cancel the operation 63 | static Future createFromDirectory( 64 | {required Directory sourceDir, 65 | required File zipFile, 66 | bool includeBaseDirectory = false, 67 | bool recurseSubDirs = true, 68 | OnZipping? onZipping}) async { 69 | final reportProgress = onZipping != null; 70 | if (reportProgress) { 71 | if (!_isMethodCallHandlerSet) { 72 | _channel.setMethodCallHandler(_channelMethodCallHandler); 73 | _isMethodCallHandlerSet = true; 74 | } 75 | } 76 | final jobId = ++_jobId; 77 | try { 78 | if (onZipping != null) { 79 | _onZippingHandlerByJobId[jobId] = onZipping; 80 | } 81 | 82 | await _channel.invokeMethod('zipDirectory', { 83 | 'sourceDir': sourceDir.path, 84 | 'zipFile': zipFile.path, 85 | 'recurseSubDirs': recurseSubDirs, 86 | 'includeBaseDirectory': includeBaseDirectory, 87 | 'reportProgress': reportProgress, 88 | 'jobId': jobId, 89 | }); 90 | } finally { 91 | _onZippingHandlerByJobId.remove(jobId); 92 | } 93 | } 94 | 95 | /// Compress given list of [files] and save the resulted archive to [zipFile]. 96 | /// [sourceDir] is the root directory of [files] (all [files] must reside 97 | /// under the [sourceDir]). 98 | /// 99 | /// Set [includeBaseDirectory] to true to include the directory name from 100 | /// [sourceDir] at the root of the archive. Set [includeBaseDirectory] to 101 | /// false to include only the contents of the [sourceDir]. 102 | static Future createFromFiles({ 103 | required Directory sourceDir, 104 | required List files, 105 | required File zipFile, 106 | bool includeBaseDirectory = false, 107 | }) async { 108 | var sourceDirPath = 109 | includeBaseDirectory ? sourceDir.parent.path : sourceDir.path; 110 | if (!sourceDirPath.endsWith(Platform.pathSeparator)) { 111 | sourceDirPath += Platform.pathSeparator; 112 | } 113 | 114 | final sourceDirPathLen = sourceDirPath.length; 115 | 116 | final relativeFilePaths = []; 117 | for (final f in files) { 118 | if (!f.path.startsWith(sourceDirPath)) { 119 | throw Exception('Files must reside under the rootDir'); 120 | } 121 | final relativeFilePath = f.path.substring(sourceDirPathLen); 122 | assert(!relativeFilePath.startsWith(Platform.pathSeparator)); 123 | relativeFilePaths.add(relativeFilePath); 124 | } 125 | await _channel.invokeMethod('zipFiles', { 126 | 'sourceDir': sourceDir.path, 127 | 'files': relativeFilePaths, 128 | 'zipFile': zipFile.path, 129 | 'includeBaseDirectory': includeBaseDirectory 130 | }); 131 | } 132 | 133 | /// Extract [zipFile] to a given [destinationDir]. Optional callback function 134 | /// [onExtracting] is called before extracting a zip entry. 135 | /// 136 | /// [onExtracting] must return one of the following values: 137 | /// [ZipFileOperation.includeItem] - extract this file/directory 138 | /// [ZipFileOperation.skipItem] - do not extract this file/directory 139 | /// [ZipFileOperation.cancel] - cancel the operation 140 | /// 141 | /// In iOS and Android (API level >= 24) you can also specify the charset 142 | /// [zipFileCharset] to be used to decode the ZIP entry names and comments. 143 | /// The enum [Charsets] defines the most common values 144 | /// (use e.g. [Charsets.UTF_8.name]). 145 | /// More information: https://developer.android.com/reference/java/util/zip/ZipFile#ZipFile(java.lang.String,%20java.nio.charset.Charset) 146 | static Future extractToDirectory({ 147 | required File zipFile, 148 | required Directory destinationDir, 149 | OnExtracting? onExtracting, 150 | String? zipFileCharset, 151 | }) async { 152 | final reportProgress = onExtracting != null; 153 | if (reportProgress) { 154 | if (!_isMethodCallHandlerSet) { 155 | _channel.setMethodCallHandler(_channelMethodCallHandler); 156 | _isMethodCallHandlerSet = true; 157 | } 158 | } 159 | final jobId = ++_jobId; 160 | try { 161 | if (onExtracting != null) { 162 | _onExtractingHandlerByJobId[jobId] = onExtracting; 163 | } 164 | 165 | await _channel.invokeMethod('unzip', { 166 | 'zipFile': zipFile.path, 167 | 'zipFileCharset': zipFileCharset, 168 | 'destinationDir': destinationDir.path, 169 | 'reportProgress': reportProgress, 170 | 'jobId': jobId, 171 | }); 172 | } finally { 173 | _onExtractingHandlerByJobId.remove(jobId); 174 | } 175 | } 176 | 177 | static bool _isMethodCallHandlerSet = false; 178 | static int _jobId = 0; 179 | static final _onExtractingHandlerByJobId = {}; 180 | static final _onZippingHandlerByJobId = {}; 181 | 182 | static Future _channelMethodCallHandler(MethodCall call) { 183 | if (call.method == 'progress') { 184 | final args = Map.from(call.arguments as Map); 185 | final jobId = args["jobId"] as int? ?? 0; 186 | final zipEntry = ZipEntry.fromMap(args); 187 | final progress = args["progress"] as double? ?? 0; 188 | final onExtractHandler = _onExtractingHandlerByJobId[jobId]; 189 | if (onExtractHandler != null) { 190 | final result = onExtractHandler(zipEntry, progress); 191 | return Future.value(result.name); 192 | } else { 193 | final onZippingHandler = _onZippingHandlerByJobId[jobId]; 194 | if (onZippingHandler != null) { 195 | final result = 196 | onZippingHandler(zipEntry.name, zipEntry.isDirectory, progress); 197 | return Future.value(result.name); 198 | } else { 199 | return Future.value(); 200 | } 201 | } 202 | } 203 | return Future.value(); 204 | } 205 | } 206 | 207 | enum CompressionMethod { none, deflated } 208 | 209 | class ZipEntry { 210 | const ZipEntry({ 211 | required this.name, 212 | required this.isDirectory, 213 | this.modificationDate, 214 | this.uncompressedSize, 215 | this.compressedSize, 216 | this.crc, 217 | this.compressionMethod, 218 | }); 219 | 220 | factory ZipEntry.fromMap(Map map) { 221 | return ZipEntry( 222 | name: map['name'] as String? ?? '', 223 | isDirectory: (map['isDirectory'] as bool?) == true, 224 | modificationDate: DateTime.fromMillisecondsSinceEpoch( 225 | map['modificationDate'] as int? ?? 0), 226 | uncompressedSize: map['uncompressedSize'] as int?, 227 | compressedSize: map['compressedSize'] as int?, 228 | crc: map['crc'] as int?, 229 | compressionMethod: map['compressionMethod'] == 'none' 230 | ? CompressionMethod.none 231 | : CompressionMethod.deflated, 232 | ); 233 | } 234 | 235 | final String name; 236 | final bool isDirectory; 237 | final DateTime? modificationDate; 238 | final int? uncompressedSize; 239 | final int? compressedSize; 240 | final int? crc; 241 | final CompressionMethod? compressionMethod; 242 | } 243 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'dart:async'; 5 | 6 | import 'package:flutter/services.dart'; 7 | import 'package:flutter_archive/flutter_archive.dart'; 8 | 9 | void main() => runApp(MyApp()); 10 | 11 | class MyApp extends StatefulWidget { 12 | @override 13 | _MyAppState createState() => _MyAppState(); 14 | } 15 | 16 | class _MyAppState extends State { 17 | @override 18 | void initState() { 19 | super.initState(); 20 | } 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | return MaterialApp( 25 | home: Scaffold( 26 | appBar: AppBar( 27 | title: const Text('Plugin test app'), 28 | ), 29 | body: Center( 30 | child: ElevatedButton( 31 | onPressed: _test, 32 | child: const Text("Test"), 33 | ), 34 | ), 35 | ), 36 | ); 37 | } 38 | 39 | final _appDataDir = Directory.systemTemp; 40 | 41 | static const _dataFilesBaseDirectoryName = "store"; 42 | final _dataFiles = { 43 | "file1.txt": "abc", 44 | "file2.txt": "åäö", 45 | "subdir1/file3.txt": r"@_£$", 46 | "subdir1/subdir11/file4.txt": "123", 47 | }; 48 | 49 | Future _test() async { 50 | print("Start test"); 51 | // test createFromDirectory 52 | // case 1 53 | var zipFile = await _testZip(includeBaseDirectory: false, progress: true); 54 | await _testUnzip(zipFile, zipIncludesBaseDirectory: false); 55 | await _testUnzip(zipFile, progress: true); 56 | // case 2 57 | zipFile = await _testZip(includeBaseDirectory: true, progress: false); 58 | await _testUnzip(zipFile, zipIncludesBaseDirectory: true); 59 | 60 | // test createFromFiles 61 | // case 1 62 | zipFile = await _testZipFiles(includeBaseDirectory: false); 63 | await _testUnzip(zipFile, zipIncludesBaseDirectory: false); 64 | // case 2 65 | zipFile = await _testZipFiles(includeBaseDirectory: true); 66 | await _testUnzip(zipFile, zipIncludesBaseDirectory: true); 67 | 68 | print("DONE!"); 69 | } 70 | 71 | Future _testZip( 72 | {required bool includeBaseDirectory, bool progress = false}) async { 73 | print("_appDataDir=${_appDataDir.path}"); 74 | final storeDir = 75 | Directory("${_appDataDir.path}${"/$_dataFilesBaseDirectoryName"}"); 76 | 77 | _createTestFiles(storeDir); 78 | 79 | final zipFile = _createZipFile("testZip.zip"); 80 | print("Writing to zip file: ${zipFile.path}"); 81 | 82 | int onProgressCallCount1 = 0; 83 | 84 | try { 85 | await ZipFile.createFromDirectory( 86 | sourceDir: storeDir, 87 | zipFile: zipFile, 88 | recurseSubDirs: true, 89 | includeBaseDirectory: includeBaseDirectory, 90 | onZipping: progress 91 | ? (fileName, isDirectory, progress) { 92 | ++onProgressCallCount1; 93 | print('Zip #1:'); 94 | print('progress: ${progress.toStringAsFixed(1)}%'); 95 | print('name: $fileName'); 96 | print('isDirectory: $isDirectory'); 97 | return ZipFileOperation.includeItem; 98 | } 99 | : null, 100 | ); 101 | assert(!progress || onProgressCallCount1 > 0); 102 | } on PlatformException catch (e) { 103 | print(e); 104 | } 105 | return zipFile; 106 | } 107 | 108 | Future _testZipFiles({required bool includeBaseDirectory}) async { 109 | print("_appDataDir=${_appDataDir.path}"); 110 | final storeDir = 111 | Directory("${_appDataDir.path}${"/$_dataFilesBaseDirectoryName"}"); 112 | 113 | final testFiles = _createTestFiles(storeDir); 114 | 115 | final zipFile = _createZipFile("testZipFiles.zip"); 116 | print("Writing files to zip file: ${zipFile.path}"); 117 | 118 | try { 119 | await ZipFile.createFromFiles( 120 | sourceDir: storeDir, 121 | files: testFiles, 122 | zipFile: zipFile, 123 | includeBaseDirectory: includeBaseDirectory); 124 | } on PlatformException catch (e) { 125 | print(e); 126 | } 127 | return zipFile; 128 | } 129 | 130 | Future _testUnzip(File zipFile, 131 | {bool progress = false, bool zipIncludesBaseDirectory = false}) async { 132 | print("_appDataDir=${_appDataDir.path}"); 133 | 134 | final destinationDir = Directory("${_appDataDir.path}/unzip"); 135 | final destinationDir2 = Directory("${_appDataDir.path}/unzip2"); 136 | 137 | if (destinationDir.existsSync()) { 138 | print("Deleting existing unzip directory: ${destinationDir.path}"); 139 | destinationDir.deleteSync(recursive: true); 140 | } 141 | if (destinationDir2.existsSync()) { 142 | print("Deleting existing unzip directory: ${destinationDir2.path}"); 143 | destinationDir2.deleteSync(recursive: true); 144 | } 145 | 146 | print("Extracting zip to directory: ${destinationDir.path}"); 147 | destinationDir.createSync(); 148 | // test concurrent extraction 149 | final extractFutures = []; 150 | int onExtractingCallCount1 = 0; 151 | int onExtractingCallCount2 = 0; 152 | try { 153 | extractFutures.add(ZipFile.extractToDirectory( 154 | zipFile: zipFile, 155 | destinationDir: destinationDir, 156 | onExtracting: progress 157 | ? (zipEntry, progress) { 158 | ++onExtractingCallCount1; 159 | print('Extract #1:'); 160 | print('progress: ${progress.toStringAsFixed(1)}%'); 161 | print('name: ${zipEntry.name}'); 162 | print('isDirectory: ${zipEntry.isDirectory}'); 163 | print( 164 | 'modificationDate: ${zipEntry.modificationDate!.toLocal().toIso8601String()}'); 165 | print('uncompressedSize: ${zipEntry.uncompressedSize}'); 166 | print('compressedSize: ${zipEntry.compressedSize}'); 167 | print('compressionMethod: ${zipEntry.compressionMethod}'); 168 | print('crc: ${zipEntry.crc}'); 169 | return ZipFileOperation.includeItem; 170 | } 171 | : null)); 172 | 173 | extractFutures.add(ZipFile.extractToDirectory( 174 | zipFile: zipFile, 175 | destinationDir: destinationDir2, 176 | onExtracting: progress 177 | ? (zipEntry, progress) { 178 | ++onExtractingCallCount2; 179 | print('Extract #2:'); 180 | print('progress: ${progress.toStringAsFixed(1)}%'); 181 | print('name: ${zipEntry.name}'); 182 | print('isDirectory: ${zipEntry.isDirectory}'); 183 | print( 184 | 'modificationDate: ${zipEntry.modificationDate!.toLocal().toIso8601String()}'); 185 | print('uncompressedSize: ${zipEntry.uncompressedSize}'); 186 | print('compressedSize: ${zipEntry.compressedSize}'); 187 | print('compressionMethod: ${zipEntry.compressionMethod}'); 188 | print('crc: ${zipEntry.crc}'); 189 | return ZipFileOperation.includeItem; 190 | } 191 | : null)); 192 | 193 | await Future.wait(extractFutures); 194 | assert(onExtractingCallCount1 == onExtractingCallCount2); 195 | assert(!progress || onExtractingCallCount1 > 0); 196 | } on PlatformException catch (e) { 197 | print(e); 198 | } 199 | 200 | // verify unzipped files 201 | if (zipIncludesBaseDirectory) { 202 | _verifyFiles( 203 | Directory("${destinationDir.path}/$_dataFilesBaseDirectoryName")); 204 | _verifyFiles( 205 | Directory("${destinationDir2.path}/$_dataFilesBaseDirectoryName")); 206 | } else { 207 | _verifyFiles(destinationDir); 208 | _verifyFiles(destinationDir2); 209 | } 210 | } 211 | 212 | File _createZipFile(String fileName) { 213 | final zipFilePath = "${_appDataDir.path}/$fileName"; 214 | final zipFile = File(zipFilePath); 215 | 216 | if (zipFile.existsSync()) { 217 | print("Deleting existing zip file: ${zipFile.path}"); 218 | zipFile.deleteSync(); 219 | } 220 | return zipFile; 221 | } 222 | 223 | List _createTestFiles(Directory storeDir) { 224 | if (storeDir.existsSync()) { 225 | storeDir.deleteSync(recursive: true); 226 | } 227 | storeDir.createSync(); 228 | final files = []; 229 | for (final fileName in _dataFiles.keys) { 230 | final file = File("${storeDir.path}/$fileName"); 231 | file.createSync(recursive: true); 232 | print("Writing file: ${file.path}"); 233 | file.writeAsStringSync(_dataFiles[fileName]!); 234 | files.add(file); 235 | } 236 | 237 | // verify created files 238 | _verifyFiles(storeDir); 239 | 240 | return files; 241 | } 242 | 243 | void _verifyFiles(Directory filesDir) { 244 | print("Verifying files at: ${filesDir.path}"); 245 | final extractedItems = filesDir.listSync(recursive: true); 246 | for (final item in extractedItems) { 247 | print("extractedItem: ${item.path}"); 248 | } 249 | print("File count: ${extractedItems.length}"); 250 | assert(extractedItems.whereType().length == _dataFiles.length, 251 | "Invalid number of files"); 252 | for (final fileName in _dataFiles.keys) { 253 | final file = File('${filesDir.path}/$fileName'); 254 | print("Verifying file: ${file.path}"); 255 | assert(file.existsSync(), "File not found: ${file.path}"); 256 | final content = file.readAsStringSync(); 257 | assert(content == _dataFiles[fileName], 258 | "Invalid file content: ${file.path}"); 259 | } 260 | print("All files ok"); 261 | } 262 | } 263 | -------------------------------------------------------------------------------- /ios/Classes/SwiftFlutterArchivePlugin.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 KineApps. All rights reserved. 2 | // 3 | // This source code is licensed under the BSD-style license found in the 4 | // LICENSE file in the root directory of this source tree. 5 | 6 | #if os(OSX) 7 | import FlutterMacOS 8 | #elseif os(iOS) 9 | import Flutter 10 | #endif 11 | 12 | /// https://github.com/weichsel/ZIPFoundation 13 | import ZIPFoundation 14 | 15 | enum ZipFileOperation: String { 16 | case includeItem 17 | case skipItem 18 | case cancel 19 | } 20 | 21 | public class SwiftFlutterArchivePlugin: NSObject, FlutterPlugin { 22 | init(_ channel: FlutterMethodChannel) { 23 | self.channel = channel 24 | } 25 | 26 | let channel: FlutterMethodChannel 27 | 28 | public static func register(with registrar: FlutterPluginRegistrar) { 29 | #if os(OSX) 30 | let channel = FlutterMethodChannel(name: "flutter_archive", binaryMessenger: registrar.messenger) 31 | #elseif os(iOS) 32 | let channel = FlutterMethodChannel(name: "flutter_archive", binaryMessenger: registrar.messenger()) 33 | #endif 34 | 35 | let instance = SwiftFlutterArchivePlugin(channel) 36 | registrar.addMethodCallDelegate(instance, channel: channel) 37 | } 38 | 39 | public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { 40 | log("call:" + call.method) 41 | 42 | switch call.method { 43 | case "zipDirectory": 44 | guard let args = call.arguments as? [String: Any] else { 45 | result(FlutterError(code: "INVALID_ARGUMENTS", 46 | message: "Invalid arguments", 47 | details: nil)) 48 | return 49 | } 50 | guard let sourceDir = args["sourceDir"] as? String else { 51 | result(FlutterError(code: "INVALID_ARGUMENTS", 52 | message: "Argument 'sourceDir' is missing", 53 | details: nil)) 54 | return 55 | } 56 | guard let zipFile = args["zipFile"] as? String else { 57 | result(FlutterError(code: "INVALID_ARGUMENTS", 58 | message: "Argument 'zipFile' is missing", 59 | details: nil)) 60 | return 61 | } 62 | let includeBaseDirectory = args["includeBaseDirectory"] as? Bool == true 63 | let recurseSubDirs = args["recurseSubDirs"] as? Bool == true 64 | let reportProgress = args["reportProgress"] as? Bool == true 65 | let jobId = args["jobId"] as? Int 66 | 67 | log("sourceDir: " + sourceDir) 68 | log("zipFile: " + zipFile) 69 | log("includeBaseDirectory: " + includeBaseDirectory.description) 70 | log("recurseSubDirs: " + recurseSubDirs.description) 71 | log("reportProgress: " + reportProgress.description) 72 | log("jobId: " + (jobId?.description ?? "")) 73 | 74 | DispatchQueue.global(qos: .userInitiated).async { 75 | let fileManager = FileManager() 76 | let sourceURL = URL(fileURLWithPath: sourceDir) 77 | let destinationURL = URL(fileURLWithPath: zipFile) 78 | do { 79 | if reportProgress || !recurseSubDirs { 80 | try self.zipDirectory(at: sourceURL, 81 | to: destinationURL, 82 | recurseSubDirs: recurseSubDirs, 83 | includeBaseDirectory: includeBaseDirectory, 84 | reportProgress: reportProgress, 85 | jobId: jobId) 86 | } else { 87 | try fileManager.zipItem(at: sourceURL, 88 | to: destinationURL, 89 | shouldKeepParent: includeBaseDirectory, 90 | compressionMethod: .deflate) 91 | } 92 | DispatchQueue.main.async { 93 | self.log("Created zip at: " + destinationURL.path) 94 | result(true) 95 | } 96 | } catch { 97 | DispatchQueue.main.async { 98 | self.log("Creation of ZIP archive failed with error:\(error)") 99 | result(FlutterError(code: "ZIP_ERROR", 100 | message: error.localizedDescription, 101 | details: nil)) 102 | } 103 | } 104 | } 105 | 106 | case "zipFiles": 107 | guard let args = call.arguments as? [String: Any] else { 108 | result(FlutterError(code: "INVALID_ARGUMENTS", 109 | message: "Invalid arguments", 110 | details: nil)) 111 | return 112 | } 113 | guard let sourceDir = args["sourceDir"] as? String else { 114 | result(FlutterError(code: "INVALID_ARGUMENTS", 115 | message: "Argument 'sourceDir' is missing", 116 | details: nil)) 117 | return 118 | } 119 | guard let files = args["files"] as? [String] else { 120 | result(FlutterError(code: "INVALID_ARGUMENTS", 121 | message: "Argument 'files' is missing", 122 | details: nil)) 123 | return 124 | } 125 | guard let zipFile = args["zipFile"] as? String else { 126 | result(FlutterError(code: "INVALID_ARGUMENTS", 127 | message: "Argument 'zipFile' is missing", 128 | details: nil)) 129 | return 130 | } 131 | let includeBaseDirectory = args["includeBaseDirectory"] as? Bool == true 132 | 133 | log("files: " + files.joined(separator: ",")) 134 | log("zipFile: " + zipFile) 135 | log("includeBaseDirectory: " + includeBaseDirectory.description) 136 | 137 | DispatchQueue.global(qos: .userInitiated).async { 138 | var sourceURL = URL(fileURLWithPath: sourceDir) 139 | if includeBaseDirectory { 140 | sourceURL = sourceURL.deletingLastPathComponent() 141 | } 142 | let destinationURL = URL(fileURLWithPath: zipFile) 143 | do { 144 | // create zip archive 145 | let archive = try Archive(url: destinationURL, accessMode: .create) 146 | 147 | for item in files { 148 | self.log("Adding: " + item) 149 | try archive.addEntry(with: item, relativeTo: sourceURL, compressionMethod: .deflate) 150 | } 151 | 152 | DispatchQueue.main.async { 153 | self.log("Created zip at: " + zipFile) 154 | result(true) 155 | } 156 | } catch { 157 | DispatchQueue.main.async { 158 | self.log("Creation of ZIP archive failed with error:\(error)") 159 | result(FlutterError(code: "ZIP_ERROR", 160 | message: error.localizedDescription, 161 | details: nil)) 162 | } 163 | } 164 | } 165 | 166 | case "unzip": 167 | guard let args = call.arguments as? [String: Any] else { 168 | result(FlutterError(code: "INVALID_ARGUMENTS", 169 | message: "Invalid arguments", 170 | details: nil)) 171 | return 172 | } 173 | guard let zipFile = args["zipFile"] as? String else { 174 | result(FlutterError(code: "INVALID_ARGUMENTS", 175 | message: "Argument 'zipFile' is missing", 176 | details: nil)) 177 | return 178 | } 179 | guard let destinationDir = args["destinationDir"] as? String else { 180 | result(FlutterError(code: "INVALID_ARGUMENTS", 181 | message: "Argument 'destinationDir' is missing", 182 | details: nil)) 183 | return 184 | } 185 | let reportProgress = args["reportProgress"] as? Bool 186 | let jobId = args["jobId"] as? Int 187 | let zipFileCharset = args["zipFileCharset"] as? String 188 | log("zipFile: " + zipFile) 189 | log("destinationDir: " + destinationDir) 190 | log("zipFileCharset: " + (zipFileCharset ?? "")) 191 | 192 | DispatchQueue.global(qos: .userInitiated).async { 193 | let fileManager = FileManager() 194 | let sourceURL = URL(fileURLWithPath: zipFile) 195 | let destinationURL = URL(fileURLWithPath: destinationDir) 196 | let preferredEncoding = self.charSet2Encoding(zipFileCharset: zipFileCharset) 197 | do { 198 | if reportProgress == true { 199 | try self.unzipItemAndReportProgress(at: sourceURL, to: destinationURL, jobId: jobId!, preferredEncoding: preferredEncoding) 200 | } else { 201 | try fileManager.createDirectory(at: destinationURL, withIntermediateDirectories: true, attributes: nil) 202 | try fileManager.unzipItem(at: sourceURL, to: destinationURL) 203 | } 204 | 205 | DispatchQueue.main.async { 206 | self.log("Extracted zip to: " + destinationURL.path) 207 | result(true) 208 | } 209 | } catch { 210 | DispatchQueue.main.async { 211 | self.log("Extraction of ZIP archive failed with error:\(error)") 212 | result(FlutterError(code: "UNZIP_ERROR", 213 | message: error.localizedDescription, 214 | details: nil)) 215 | } 216 | } 217 | } 218 | 219 | default: 220 | log("not implemented") 221 | result(FlutterMethodNotImplemented) 222 | } 223 | } 224 | 225 | private func charSet2Encoding(zipFileCharset: String?) ->String.Encoding? { 226 | switch (zipFileCharset) { 227 | case ("ISO_8859_1"): return String.Encoding.isoLatin1 228 | case ("US_ASCII"): return String.Encoding.ascii 229 | case ("UTF_16"): return String.Encoding.utf16 230 | case ("UTF_16BE"): return String.Encoding.utf16BigEndian 231 | case ("UTF_16LE"): return String.Encoding.utf16LittleEndian 232 | case ("UTF_8"): return String.Encoding.utf8 233 | case ("CP437"): return nil 234 | default: return nil 235 | } 236 | } 237 | 238 | private func zipDirectory(at sourceURL: URL, 239 | to zipFileURL: URL, 240 | recurseSubDirs: Bool, 241 | includeBaseDirectory: Bool, 242 | reportProgress: Bool, 243 | jobId: Int?) throws 244 | { 245 | var files = [URL]() 246 | if let enumerator = FileManager.default.enumerator( 247 | at: sourceURL, 248 | includingPropertiesForKeys: [.isRegularFileKey], 249 | options: recurseSubDirs ? 250 | [.skipsHiddenFiles, .skipsPackageDescendants] : 251 | [.skipsHiddenFiles, .skipsPackageDescendants, .skipsSubdirectoryDescendants]) 252 | { 253 | for case let fileURL as URL in enumerator { 254 | let fileAttributes = try fileURL.resourceValues(forKeys: [.isRegularFileKey]) 255 | if fileAttributes.isRegularFile! { 256 | let url = fileURL.standardizedFileURL 257 | log("Found file: " + url.path) 258 | files.append(url) 259 | } 260 | } 261 | } 262 | 263 | // create zip archive 264 | let archive = try Archive(url: zipFileURL, accessMode: .create) 265 | 266 | let totalEntriesCount = Double(files.count) 267 | var currentEntryIndex: Double = 0 268 | 269 | let dispatchGroup = DispatchGroup() 270 | 271 | let baseDirUrl = URL(fileURLWithPath: includeBaseDirectory ? 272 | sourceURL.deletingLastPathComponent().path : sourceURL.path).standardizedFileURL 273 | log("baseDirUrl: " + baseDirUrl.path) 274 | for item in files { 275 | if reportProgress { 276 | log("File: " + item.path) 277 | currentEntryIndex += 1 278 | let progress: Double = currentEntryIndex / totalEntriesCount * 100.0 279 | 280 | let entryDic: [String: Any] = [ 281 | "name": item.path, 282 | "isDirectory": item.isDirectory, 283 | "jobId": jobId!, 284 | "progress": progress, 285 | ] 286 | 287 | var extractOperation: ZipFileOperation? 288 | dispatchGroup.enter() 289 | DispatchQueue.main.async { 290 | self.channel.invokeMethod("progress", arguments: entryDic) { 291 | (result: Any?) -> Void in 292 | if let error = result as? FlutterError { 293 | self.log("failed: \(error)") 294 | extractOperation = ZipFileOperation.includeItem 295 | } else if FlutterMethodNotImplemented.isEqual(result) { 296 | self.log("not implemented") 297 | extractOperation = ZipFileOperation.includeItem 298 | } else { 299 | extractOperation = ZipFileOperation(rawValue: result as! String) 300 | self.log("result: \(String(describing: extractOperation))") 301 | } 302 | dispatchGroup.leave() 303 | } 304 | } 305 | 306 | 307 | log("Waiting...") 308 | dispatchGroup.wait() 309 | log("..waiting") 310 | if extractOperation == ZipFileOperation.skipItem { 311 | log("skip") 312 | continue 313 | } else if extractOperation == ZipFileOperation.cancel { 314 | log("cancel") 315 | break 316 | } 317 | } 318 | 319 | let relativePath = item.path.replacingFirstOccurrence(of: baseDirUrl.path + "/", with: "") 320 | log("Adding: " + relativePath) 321 | try archive.addEntry(with: relativePath, relativeTo: baseDirUrl, compressionMethod: .deflate) 322 | } 323 | } 324 | 325 | /// Unzips the contents at the specified source URL to the destination URL. 326 | /// 327 | /// - Parameters: 328 | /// - sourceURL: The file URL pointing to an existing ZIP file. 329 | /// - destinationURL: The file URL that identifies the destination directory of the unzip operation. 330 | /// - jobId: Job id 331 | /// - skipCRC32: Optional flag to skip calculation of the CRC32 checksum to improve performance. 332 | /// - preferredEncoding: Encoding for entry paths. Overrides the encoding specified in the archive. 333 | /// - Throws: Throws an error if the source item does not exist or the destination URL is not writable. 334 | private func unzipItemAndReportProgress(at sourceURL: URL, to destinationURL: URL, jobId: Int, skipCRC32: Bool = false, 335 | preferredEncoding: String.Encoding? = nil) throws 336 | { 337 | // based on https://github.com/weichsel/ZIPFoundation/blob/development/Sources/ZIPFoundation/FileManager%2BZIP.swift 338 | guard itemExists(at: sourceURL) else { 339 | throw CocoaError(.fileReadNoSuchFile, userInfo: [NSFilePathErrorKey: sourceURL.path]) 340 | } 341 | let archive = try Archive(url: sourceURL, accessMode: .read, pathEncoding: preferredEncoding) 342 | 343 | // Defer extraction of symlinks until all files & directories have been created. 344 | // This is necessary because we can't create links to files that haven't been created yet. 345 | let sortedEntries = archive.sorted { (left, right) -> Bool in 346 | switch (left.type, right.type) { 347 | case (.directory, .file): return true 348 | case (.directory, .symlink): return true 349 | case (.file, .symlink): return true 350 | default: return false 351 | } 352 | } 353 | 354 | let totalEntriesCount = Double(sortedEntries.count) 355 | var currentEntryIndex: Double = 0 356 | 357 | let dispatchGroup = DispatchGroup() 358 | for entry in sortedEntries { 359 | let path = preferredEncoding == nil ? entry.path : entry.path(using: preferredEncoding!) 360 | let destinationEntryURL = destinationURL.appendingPathComponent(path) 361 | 362 | var entryDic = entryToDictionary(entry: entry, preferredEncoding: preferredEncoding) 363 | currentEntryIndex += 1 364 | let progress: Double = currentEntryIndex / totalEntriesCount * 100.0 365 | entryDic["jobId"] = jobId 366 | entryDic["progress"] = progress 367 | var extractOperation: ZipFileOperation? 368 | dispatchGroup.enter() 369 | DispatchQueue.main.async { 370 | self.channel.invokeMethod("progress", arguments: entryDic) { 371 | (result: Any?) -> Void in 372 | if let error = result as? FlutterError { 373 | self.log("failed: \(error)") 374 | extractOperation = ZipFileOperation.includeItem 375 | } else if FlutterMethodNotImplemented.isEqual(result) { 376 | self.log("not implemented") 377 | extractOperation = ZipFileOperation.includeItem 378 | } else { 379 | extractOperation = ZipFileOperation(rawValue: result as! String) 380 | self.log("result: \(String(describing: extractOperation))") 381 | } 382 | dispatchGroup.leave() 383 | } 384 | } 385 | 386 | log("Waiting...") 387 | dispatchGroup.wait() 388 | log("..waiting") 389 | if extractOperation == ZipFileOperation.skipItem { 390 | log("skip") 391 | continue 392 | } else if extractOperation == ZipFileOperation.cancel { 393 | log("cancel") 394 | break 395 | } 396 | 397 | guard destinationEntryURL.isContained(in: destinationURL) else { 398 | throw CocoaError(.fileReadInvalidFileName, 399 | userInfo: [NSFilePathErrorKey: destinationEntryURL.path]) 400 | } 401 | _ = try archive.extract(entry, to: destinationEntryURL, skipCRC32: skipCRC32) 402 | } 403 | } 404 | 405 | // MARK: - Helpers 406 | 407 | // https://github.com/weichsel/ZIPFoundation/blob/development/Sources/ZIPFoundation/FileManager%2BZIP.swift 408 | private func itemExists(at url: URL) -> Bool { 409 | // Use `URL.checkResourceIsReachable()` instead of `FileManager.fileExists()` here 410 | // because we don't want implicit symlink resolution. 411 | // As per documentation, `FileManager.fileExists()` traverses symlinks and therefore a broken symlink 412 | // would throw a `.fileReadNoSuchFile` false positive error. 413 | // For ZIP files it may be intended to archive "broken" symlinks because they might be 414 | // resolvable again when extracting the archive to a different destination. 415 | return (try? url.checkResourceIsReachable()) == true 416 | } 417 | 418 | /// https://github.com/flutter/flutter/issues/13204 419 | private func log(_ message: String) { 420 | NSLog("\n" + message) 421 | } 422 | 423 | private func entryToDictionary(entry: Entry, preferredEncoding: String.Encoding? = nil) -> [String: Any] { 424 | let date = entry.fileAttributes[FileAttributeKey.modificationDate] as? Date 425 | let millis = Int(date?.timeIntervalSince1970 ?? 0) * 1000 426 | let dic: [String: Any] = [ 427 | "name": preferredEncoding == nil ? entry.path : entry.path(using: preferredEncoding!), 428 | "isDirectory": entry.type == Entry.EntryType.directory, 429 | "modificationDate": millis, 430 | "uncompressedSize": entry.uncompressedSize, 431 | "compressedSize": entry.compressedSize, 432 | "crc": entry.checksum, 433 | "compressionMethod": entry.compressedSize != entry.uncompressedSize ? "deflated" : "none", 434 | ] 435 | return dic 436 | } 437 | } 438 | 439 | extension URL { 440 | var isDirectory: Bool { 441 | return (try? resourceValues(forKeys: [.isDirectoryKey]))?.isDirectory == true 442 | } 443 | } 444 | 445 | extension String { 446 | func replacingFirstOccurrence(of target: String, with replacement: String) -> String { 447 | guard let range = self.range(of: target) else { return self } 448 | return replacingCharacters(in: range, with: replacement) 449 | } 450 | } 451 | -------------------------------------------------------------------------------- /android/src/main/kotlin/com/kineapps/flutterarchive/FlutterArchivePlugin.kt: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2022 KineApps. All rights reserved. 2 | // 3 | // This source code is licensed under the BSD-style license found in the 4 | // LICENSE file in the root directory of this source tree. 5 | 6 | package com.kineapps.flutterarchive 7 | 8 | import android.os.Build 9 | import android.util.Log 10 | import io.flutter.embedding.engine.plugins.FlutterPlugin 11 | import io.flutter.plugin.common.BinaryMessenger 12 | import io.flutter.plugin.common.MethodCall 13 | import io.flutter.plugin.common.MethodChannel 14 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler 15 | import io.flutter.plugin.common.MethodChannel.Result 16 | import kotlinx.coroutines.CancellationException 17 | import kotlinx.coroutines.CompletableDeferred 18 | import kotlinx.coroutines.CoroutineScope 19 | import kotlinx.coroutines.Dispatchers 20 | import kotlinx.coroutines.launch 21 | import kotlinx.coroutines.withContext 22 | import java.io.BufferedOutputStream 23 | import java.io.Closeable 24 | import java.io.File 25 | import java.io.FileInputStream 26 | import java.io.FileOutputStream 27 | import java.io.IOException 28 | import java.nio.charset.Charset 29 | import java.util.zip.ZipEntry 30 | import java.util.zip.ZipEntry.DEFLATED 31 | import java.util.zip.ZipFile 32 | import java.util.zip.ZipOutputStream 33 | 34 | enum class ZipFileOperation { INCLUDE_ITEM, SKIP_ITEM, CANCEL } 35 | 36 | /** 37 | * FlutterArchivePlugin 38 | */ 39 | class FlutterArchivePlugin : FlutterPlugin, MethodCallHandler { 40 | private var pluginBinding: FlutterPlugin.FlutterPluginBinding? = null 41 | private var methodChannel: MethodChannel? = null 42 | 43 | companion object { 44 | private const val LOG_TAG = "FlutterArchivePlugin" 45 | } 46 | 47 | override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) { 48 | Log.d(LOG_TAG, "onAttachedToEngine - IN") 49 | 50 | if (pluginBinding != null) { 51 | Log.w(LOG_TAG, "onAttachedToEngine - already attached") 52 | } 53 | 54 | pluginBinding = binding 55 | 56 | val messenger = pluginBinding?.binaryMessenger 57 | doOnAttachedToEngine(messenger!!) 58 | 59 | Log.d(LOG_TAG, "onAttachedToEngine - OUT") 60 | } 61 | 62 | override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { 63 | Log.d(LOG_TAG, "onDetachedFromEngine") 64 | doOnDetachedFromEngine() 65 | } 66 | 67 | private fun doOnAttachedToEngine(messenger: BinaryMessenger) { 68 | Log.d(LOG_TAG, "doOnAttachedToEngine - IN") 69 | 70 | methodChannel = MethodChannel(messenger, "flutter_archive") 71 | methodChannel?.setMethodCallHandler(this) 72 | 73 | Log.d(LOG_TAG, "doOnAttachedToEngine - OUT") 74 | } 75 | 76 | private fun doOnDetachedFromEngine() { 77 | Log.d(LOG_TAG, "doOnDetachedFromEngine - IN") 78 | 79 | if (pluginBinding == null) { 80 | Log.w(LOG_TAG, "doOnDetachedFromEngine - already detached") 81 | } 82 | pluginBinding = null 83 | 84 | methodChannel?.setMethodCallHandler(null) 85 | methodChannel = null 86 | 87 | Log.d(LOG_TAG, "doOnDetachedFromEngine - OUT") 88 | } 89 | 90 | override fun onMethodCall(call: MethodCall, result: Result) { 91 | val uiScope = CoroutineScope(Dispatchers.Main) 92 | 93 | when (call.method) { 94 | "zipDirectory" -> { 95 | uiScope.launch { 96 | try { 97 | val sourceDir = call.argument("sourceDir") 98 | val zipFile = call.argument("zipFile") 99 | val recurseSubDirs = call.argument("recurseSubDirs") == true 100 | val includeBaseDirectory = 101 | call.argument("includeBaseDirectory") == true 102 | val reportProgress = call.argument("reportProgress") 103 | val jobId = call.argument("jobId") 104 | 105 | withContext(Dispatchers.IO) { 106 | zip( 107 | sourceDirPath = sourceDir!!, 108 | zipFilePath = zipFile!!, 109 | recurseSubDirs = recurseSubDirs, 110 | includeBaseDirectory = includeBaseDirectory, 111 | reportProgress = reportProgress == true, 112 | jobId = jobId!! 113 | ) 114 | } 115 | result.success(true) 116 | } catch (e: Exception) { 117 | e.printStackTrace() 118 | result.error("zip_error", e.localizedMessage, e.toString()) 119 | } 120 | } 121 | } 122 | "zipFiles" -> { 123 | uiScope.launch { 124 | try { 125 | val sourceDir = call.argument("sourceDir") 126 | val files = call.argument>("files") 127 | val zipFile = call.argument("zipFile") 128 | val includeBaseDirectory = 129 | call.argument("includeBaseDirectory") == true 130 | 131 | withContext(Dispatchers.IO) { 132 | zipFiles(sourceDir!!, files!!, zipFile!!, includeBaseDirectory) 133 | } 134 | result.success(true) 135 | } catch (e: Exception) { 136 | e.printStackTrace() 137 | result.error("zip_error", e.localizedMessage, e.toString()) 138 | } 139 | } 140 | } 141 | "unzip" -> { 142 | uiScope.launch { 143 | try { 144 | val zipFile = call.argument("zipFile") 145 | val zipFileCharset = call.argument("zipFileCharset") 146 | val destinationDir = call.argument("destinationDir") 147 | val reportProgress = call.argument("reportProgress") 148 | val jobId = call.argument("jobId") 149 | 150 | val charset = zipFileCharset?.let { Charset.forName(zipFileCharset) } 151 | 152 | Log.d(LOG_TAG, "onMethodCall / unzip...") 153 | withContext(Dispatchers.IO) { 154 | unzip( 155 | zipFilePath = zipFile!!, 156 | zipFileCharSet = charset, 157 | destinationDirPath = destinationDir!!, 158 | reportProgress = reportProgress == true, 159 | jobId = jobId!! 160 | ) 161 | } 162 | Log.d(LOG_TAG, "...onMethodCall / unzip") 163 | result.success(true) 164 | } catch (e: Exception) { 165 | e.printStackTrace() 166 | result.error("unzip_error", e.localizedMessage, e.toString()) 167 | } 168 | } 169 | } 170 | else -> result.notImplemented() 171 | } 172 | } 173 | 174 | @Throws(IOException::class) 175 | private suspend fun zip( 176 | sourceDirPath: String, 177 | zipFilePath: String, 178 | recurseSubDirs: Boolean, 179 | includeBaseDirectory: Boolean, 180 | reportProgress: Boolean, 181 | jobId: Int 182 | ) { 183 | Log.i( 184 | "zip", 185 | "sourceDirPath: $sourceDirPath, zipFilePath: $zipFilePath, recurseSubDirs: $recurseSubDirs, includeBaseDirectory: $includeBaseDirectory" 186 | ) 187 | 188 | val rootDirectory = 189 | if (includeBaseDirectory) File(sourceDirPath).parentFile else File(sourceDirPath) 190 | 191 | val totalFileCount = if (reportProgress) getFilesCount(rootDirectory, recurseSubDirs) else 0 192 | 193 | withContext(Dispatchers.IO) { 194 | ZipOutputStream( 195 | BufferedOutputStream( 196 | FileOutputStream(zipFilePath) 197 | ) 198 | ).use { zipOutputStream -> 199 | addFilesInDirectoryToZip( 200 | zipOutputStream = zipOutputStream, 201 | rootDirectory = rootDirectory, 202 | directoryPath = sourceDirPath, 203 | recurseSubDirs = recurseSubDirs, 204 | reportProgress = reportProgress, 205 | jobId = jobId, 206 | totalFilesCount = totalFileCount, 207 | totalHandledFilesCount = 0 208 | ) 209 | } 210 | } 211 | } 212 | 213 | /** 214 | * Add all files in [rootDirectory] to [zipOutputStream]. 215 | * 216 | * @return Updated total number of handled files 217 | */ 218 | private suspend fun addFilesInDirectoryToZip( 219 | zipOutputStream: ZipOutputStream, 220 | rootDirectory: File, 221 | directoryPath: String, 222 | recurseSubDirs: Boolean, 223 | reportProgress: Boolean, 224 | jobId: Int, 225 | totalFilesCount: Int, 226 | totalHandledFilesCount: Int 227 | ): Int { 228 | val directory = File(directoryPath) 229 | 230 | val files = directory.listFiles() ?: arrayOf() 231 | var handledFilesCount = totalHandledFilesCount 232 | for (f in files) { 233 | val path = directoryPath + File.separator + f.name 234 | val relativePath = File(path).relativeTo(rootDirectory).path 235 | 236 | if (f.isDirectory) { 237 | // include subdirectories only if requested 238 | if (!recurseSubDirs) { 239 | continue 240 | } 241 | Log.i("zip", "Adding directory: $relativePath") 242 | 243 | // add directory entry 244 | val entry = ZipEntry(relativePath + File.separator) 245 | entry.time = f.lastModified() 246 | entry.size = f.length() 247 | 248 | if (reportProgress) { 249 | // report progress 250 | val progress: Double = 251 | handledFilesCount.toDouble() / totalFilesCount.toDouble() * 100.0 252 | 253 | Log.d(LOG_TAG, "Waiting reportProgress...") 254 | val zipFileOperation = reportProgress(jobId, entry, progress) 255 | Log.d(LOG_TAG, "...reportProgress: $zipFileOperation") 256 | 257 | if (zipFileOperation == ZipFileOperation.SKIP_ITEM) { 258 | continue 259 | } else if (zipFileOperation == ZipFileOperation.CANCEL) { 260 | throw CancellationException("Operation cancelled") 261 | } 262 | } 263 | 264 | withContext(Dispatchers.IO) { 265 | zipOutputStream.putNextEntry(entry) 266 | } 267 | 268 | // zip files and subdirectories in this directory 269 | handledFilesCount = addFilesInDirectoryToZip( 270 | zipOutputStream = zipOutputStream, 271 | rootDirectory = rootDirectory, 272 | directoryPath = path, 273 | recurseSubDirs = true, 274 | reportProgress = reportProgress, 275 | jobId = jobId, 276 | totalFilesCount = totalFilesCount, 277 | totalHandledFilesCount = handledFilesCount 278 | ) 279 | } else { 280 | Log.i("zip", "Adding file: $relativePath") 281 | ++handledFilesCount 282 | withContext(Dispatchers.IO) { 283 | FileInputStream(f).use { fileInputStream -> 284 | val entry = ZipEntry(relativePath) 285 | entry.time = f.lastModified() 286 | entry.size = f.length() 287 | 288 | if (reportProgress) { 289 | // report progress 290 | val progress: Double = 291 | handledFilesCount.toDouble() / totalFilesCount.toDouble() * 100.0 292 | 293 | Log.d(LOG_TAG, "Waiting reportProgress...") 294 | val zipFileOperation = reportProgress(jobId, entry, progress) 295 | Log.d(LOG_TAG, "...reportProgress: $zipFileOperation") 296 | 297 | when (zipFileOperation) { 298 | ZipFileOperation.INCLUDE_ITEM -> { 299 | zipOutputStream.putNextEntry(entry) 300 | fileInputStream.copyTo(zipOutputStream) 301 | } 302 | ZipFileOperation.CANCEL -> { 303 | throw CancellationException("Operation cancelled") 304 | } 305 | else -> { 306 | // skip this entry 307 | } 308 | } 309 | } else { 310 | zipOutputStream.putNextEntry(entry) 311 | fileInputStream.copyTo(zipOutputStream) 312 | } 313 | } 314 | } 315 | } 316 | } 317 | return handledFilesCount 318 | } 319 | 320 | @Throws(IOException::class) 321 | private fun zipFiles( 322 | sourceDirPath: String, 323 | relativeFilePaths: List, 324 | zipFilePath: String, 325 | includeBaseDirectory: Boolean 326 | ) { 327 | Log.i( 328 | "zip", 329 | "sourceDirPath: $sourceDirPath, " + 330 | "zipFilePath: $zipFilePath, " + 331 | "includeBaseDirectory: $includeBaseDirectory" 332 | ) 333 | Log.i("zip", "Files: ${relativeFilePaths.joinToString(",")}") 334 | 335 | val rootDirectory = 336 | if (includeBaseDirectory) File(sourceDirPath).parentFile else File(sourceDirPath) 337 | 338 | ZipOutputStream( 339 | BufferedOutputStream( 340 | FileOutputStream(zipFilePath) 341 | ) 342 | ).use { zipOutputStream -> 343 | for (relativeFilePath in relativeFilePaths) { 344 | val file = rootDirectory.resolve(relativeFilePath) 345 | val cleanedRelativeFilePath = file.relativeTo(rootDirectory).path 346 | Log.i("zip", "Adding file: $cleanedRelativeFilePath") 347 | FileInputStream(file).use { fileInputStream -> 348 | val entry = ZipEntry(cleanedRelativeFilePath) 349 | entry.time = file.lastModified() 350 | entry.size = file.length() 351 | zipOutputStream.putNextEntry(entry) 352 | fileInputStream.copyTo(zipOutputStream) 353 | } 354 | } 355 | } 356 | } 357 | 358 | @Throws(IOException::class) 359 | private suspend fun unzip( 360 | zipFilePath: String, 361 | zipFileCharSet: Charset?, 362 | destinationDirPath: String, 363 | reportProgress: Boolean, 364 | jobId: Int 365 | ) { 366 | val destinationDir = File(destinationDirPath) 367 | 368 | Log.d(LOG_TAG, "destinationDir.path: ${destinationDir.path}") 369 | Log.d(LOG_TAG, "destinationDir.canonicalPath: ${destinationDir.canonicalPath}") 370 | Log.d(LOG_TAG, "destinationDir.absolutePath: ${destinationDir.absolutePath}") 371 | 372 | // specify charset if unzip fails to MALFORMED exception, see for example 373 | // https://stackoverflow.com/questions/41908761/unzipping-a-file-with-special-characters-in-filenames-from-api24-upward 374 | val zipFile: ZipFile = 375 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && 376 | zipFileCharSet != null 377 | ) { 378 | ZipFile(zipFilePath, zipFileCharSet) 379 | } else { 380 | ZipFileEx(zipFilePath) 381 | } 382 | 383 | zipFile.use { 384 | val entriesCount = zipFile.size().toDouble() 385 | var currentEntryIndex = 0.0 386 | for (ze in zipFile.entries()) { 387 | val filename = ze.name 388 | Log.d( 389 | LOG_TAG, 390 | "zipEntry fileName=$filename, compressedSize=${ze.compressedSize}, size=${ze.size}, crc=${ze.crc}" 391 | ) 392 | 393 | val outputFile = File(destinationDirPath, filename) 394 | 395 | // prevent Zip Path Traversal attack 396 | // https://support.google.com/faqs/answer/9294009 397 | val outputFileCanonicalPath = outputFile.canonicalPath 398 | if (!outputFileCanonicalPath.startsWith(destinationDir.canonicalPath)) { 399 | Log.d(LOG_TAG, "outputFile path: ${outputFile.path}") 400 | Log.d(LOG_TAG, "canonicalPath: $outputFileCanonicalPath") 401 | throw SecurityException("Invalid zip file") 402 | } 403 | 404 | if (reportProgress) { 405 | // report progress 406 | val progress: Double = currentEntryIndex++ / (entriesCount - 1) * 100 407 | 408 | Log.d(LOG_TAG, "Waiting reportProgress...") 409 | val zipFileOperation = reportProgress(jobId, ze, progress) 410 | Log.d(LOG_TAG, "...reportProgress: $zipFileOperation") 411 | 412 | if (zipFileOperation == ZipFileOperation.SKIP_ITEM) { 413 | continue 414 | } else if (zipFileOperation == ZipFileOperation.CANCEL) { 415 | break 416 | } 417 | } 418 | 419 | // need to create any missing directories 420 | if (ze.isDirectory) { 421 | Log.d(LOG_TAG, "Creating directory: " + outputFile.path) 422 | outputFile.mkdirs() 423 | } else { 424 | val parentDir = outputFile.parentFile 425 | if (parentDir != null && !parentDir.exists()) { 426 | Log.d(LOG_TAG, "Creating directory: " + parentDir.path) 427 | parentDir.mkdirs() 428 | } 429 | 430 | Log.d(LOG_TAG, "Writing entry to file: " + outputFile.path) 431 | withContext(Dispatchers.IO) { 432 | zipFile.getInputStream(ze).use { zis -> 433 | outputFile.outputStream() 434 | .use { outputStream -> zis.copyTo(outputStream) } 435 | } 436 | } 437 | } 438 | } 439 | } 440 | } 441 | 442 | private suspend fun reportProgress( 443 | jobId: Int, 444 | zipEntry: ZipEntry, 445 | progress: Double 446 | ): ZipFileOperation { 447 | val map = zipEntryToMap(zipEntry).toMutableMap() 448 | map["jobId"] = jobId 449 | map["progress"] = progress 450 | 451 | val deferred = CompletableDeferred() 452 | 453 | val uiScope = CoroutineScope(Dispatchers.Main) 454 | uiScope.launch { 455 | methodChannel?.invokeMethod("progress", map, object : Result { 456 | 457 | override fun success(result: Any?) { 458 | Log.i(LOG_TAG, "invokeMethod - success: $result") 459 | when (result) { 460 | "cancel" -> { 461 | deferred.complete(ZipFileOperation.CANCEL) 462 | } 463 | "skipItem" -> { 464 | deferred.complete(ZipFileOperation.SKIP_ITEM) 465 | } 466 | else -> { 467 | deferred.complete(ZipFileOperation.INCLUDE_ITEM) 468 | } 469 | } 470 | } 471 | 472 | override fun error(code: String, msg: String?, details: Any?) { 473 | Log.e(LOG_TAG, "invokeMethod - error: $msg") 474 | // ignore error and extract normally 475 | deferred.complete(ZipFileOperation.INCLUDE_ITEM) 476 | } 477 | 478 | override fun notImplemented() { 479 | Log.e(LOG_TAG, "invokeMethod - notImplemented") 480 | // ignore error and extract normally 481 | deferred.complete(ZipFileOperation.INCLUDE_ITEM) 482 | } 483 | }) 484 | } 485 | return deferred.await() 486 | } 487 | 488 | /** 489 | * Return number of files under [dir]. Count also files in subdirectories 490 | * if [recurseSubDirs] is true. 491 | */ 492 | private fun getFilesCount(dir: File, recurseSubDirs: Boolean): Int { 493 | val fileAndDirs = dir.listFiles() 494 | var count = 0 495 | if (fileAndDirs != null) { 496 | for (f in fileAndDirs) { 497 | if (recurseSubDirs && f.isDirectory) { 498 | count += getFilesCount(f, recurseSubDirs) 499 | } else { 500 | count++ 501 | } 502 | } 503 | } 504 | return count 505 | } 506 | 507 | private fun zipEntryToMap(ze: ZipEntry): Map { 508 | return mapOf( 509 | "name" to ze.name, 510 | "isDirectory" to ze.isDirectory, 511 | "comment" to ze.comment, 512 | "modificationDate" to ze.time, 513 | "uncompressedSize" to ze.size, 514 | "compressedSize" to ze.compressedSize, 515 | "crc" to ze.crc, 516 | "compressionMethod" to (if (ze.method == DEFLATED) "deflated" else "none") 517 | ) 518 | } 519 | 520 | // This is needed because ZipFile implements Closeable only starting from API 19 and 521 | // we support >=16 522 | class ZipFileEx(name: String?) : ZipFile(name), Closeable 523 | } 524 | -------------------------------------------------------------------------------- /example/macos/Runner/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 54; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 2825EDA2B7E425A67EF2581F /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E66F8FB77AD5CD9F792F17E /* Pods_Runner.framework */; }; 12 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 13 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 14 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; 15 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 16 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 17 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXCopyFilesBuildPhase section */ 21 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 22 | isa = PBXCopyFilesBuildPhase; 23 | buildActionMask = 2147483647; 24 | dstPath = ""; 25 | dstSubfolderSpec = 10; 26 | files = ( 27 | ); 28 | name = "Embed Frameworks"; 29 | runOnlyForDeploymentPostprocessing = 0; 30 | }; 31 | /* End PBXCopyFilesBuildPhase section */ 32 | 33 | /* Begin PBXFileReference section */ 34 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 35 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 36 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 37 | 3E66F8FB77AD5CD9F792F17E /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 38 | 6C8F778387C8B87CADE0DDD9 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 39 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 40 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 41 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 42 | 7BF65B94ADA84A925396EB4A /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 43 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 44 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 45 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 47 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 48 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 49 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50 | CE6E4F333B1E1EEE26EB0103 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 51 | /* End PBXFileReference section */ 52 | 53 | /* Begin PBXFrameworksBuildPhase section */ 54 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 55 | isa = PBXFrameworksBuildPhase; 56 | buildActionMask = 2147483647; 57 | files = ( 58 | 2825EDA2B7E425A67EF2581F /* Pods_Runner.framework in Frameworks */, 59 | ); 60 | runOnlyForDeploymentPostprocessing = 0; 61 | }; 62 | /* End PBXFrameworksBuildPhase section */ 63 | 64 | /* Begin PBXGroup section */ 65 | 566540B082174A6CFE95918A /* Frameworks */ = { 66 | isa = PBXGroup; 67 | children = ( 68 | 3E66F8FB77AD5CD9F792F17E /* Pods_Runner.framework */, 69 | ); 70 | name = Frameworks; 71 | sourceTree = ""; 72 | }; 73 | 9740EEB11CF90186004384FC /* Flutter */ = { 74 | isa = PBXGroup; 75 | children = ( 76 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 77 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 78 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 79 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 80 | ); 81 | name = Flutter; 82 | sourceTree = ""; 83 | }; 84 | 97C146E51CF9000F007C117D = { 85 | isa = PBXGroup; 86 | children = ( 87 | 9740EEB11CF90186004384FC /* Flutter */, 88 | 97C146F01CF9000F007C117D /* Runner */, 89 | 97C146EF1CF9000F007C117D /* Products */, 90 | E69B4D5D2A0DB72BC2E72F88 /* Pods */, 91 | 566540B082174A6CFE95918A /* Frameworks */, 92 | ); 93 | sourceTree = ""; 94 | }; 95 | 97C146EF1CF9000F007C117D /* Products */ = { 96 | isa = PBXGroup; 97 | children = ( 98 | 97C146EE1CF9000F007C117D /* Runner.app */, 99 | ); 100 | name = Products; 101 | sourceTree = ""; 102 | }; 103 | 97C146F01CF9000F007C117D /* Runner */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 107 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 108 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 109 | 97C147021CF9000F007C117D /* Info.plist */, 110 | 97C146F11CF9000F007C117D /* Supporting Files */, 111 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 112 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 113 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 114 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 115 | ); 116 | path = Runner; 117 | sourceTree = ""; 118 | }; 119 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | ); 123 | name = "Supporting Files"; 124 | sourceTree = ""; 125 | }; 126 | E69B4D5D2A0DB72BC2E72F88 /* Pods */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | 6C8F778387C8B87CADE0DDD9 /* Pods-Runner.debug.xcconfig */, 130 | CE6E4F333B1E1EEE26EB0103 /* Pods-Runner.release.xcconfig */, 131 | 7BF65B94ADA84A925396EB4A /* Pods-Runner.profile.xcconfig */, 132 | ); 133 | path = Pods; 134 | sourceTree = ""; 135 | }; 136 | /* End PBXGroup section */ 137 | 138 | /* Begin PBXNativeTarget section */ 139 | 97C146ED1CF9000F007C117D /* Runner */ = { 140 | isa = PBXNativeTarget; 141 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 142 | buildPhases = ( 143 | 47F5A62ADCF321E3D18E1DED /* [CP] Check Pods Manifest.lock */, 144 | 9740EEB61CF901F6004384FC /* Run Script */, 145 | 97C146EA1CF9000F007C117D /* Sources */, 146 | 97C146EB1CF9000F007C117D /* Frameworks */, 147 | 97C146EC1CF9000F007C117D /* Resources */, 148 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 149 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 150 | DE45073DF0D19C85955D3576 /* [CP] Embed Pods Frameworks */, 151 | ); 152 | buildRules = ( 153 | ); 154 | dependencies = ( 155 | ); 156 | name = Runner; 157 | productName = Runner; 158 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 159 | productType = "com.apple.product-type.application"; 160 | }; 161 | /* End PBXNativeTarget section */ 162 | 163 | /* Begin PBXProject section */ 164 | 97C146E61CF9000F007C117D /* Project object */ = { 165 | isa = PBXProject; 166 | attributes = { 167 | LastUpgradeCheck = 1510; 168 | ORGANIZATIONNAME = "The Chromium Authors"; 169 | TargetAttributes = { 170 | 97C146ED1CF9000F007C117D = { 171 | CreatedOnToolsVersion = 7.3.1; 172 | DevelopmentTeam = YOUR_TEAM_ID; 173 | LastSwiftMigration = 0910; 174 | }; 175 | }; 176 | }; 177 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 178 | compatibilityVersion = "Xcode 3.2"; 179 | developmentRegion = en; 180 | hasScannedForEncodings = 0; 181 | knownRegions = ( 182 | en, 183 | Base, 184 | ); 185 | mainGroup = 97C146E51CF9000F007C117D; 186 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 187 | projectDirPath = ""; 188 | projectRoot = ""; 189 | targets = ( 190 | 97C146ED1CF9000F007C117D /* Runner */, 191 | ); 192 | }; 193 | /* End PBXProject section */ 194 | 195 | /* Begin PBXResourcesBuildPhase section */ 196 | 97C146EC1CF9000F007C117D /* Resources */ = { 197 | isa = PBXResourcesBuildPhase; 198 | buildActionMask = 2147483647; 199 | files = ( 200 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 201 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 202 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 203 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 204 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 205 | ); 206 | runOnlyForDeploymentPostprocessing = 0; 207 | }; 208 | /* End PBXResourcesBuildPhase section */ 209 | 210 | /* Begin PBXShellScriptBuildPhase section */ 211 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 212 | isa = PBXShellScriptBuildPhase; 213 | alwaysOutOfDate = 1; 214 | buildActionMask = 2147483647; 215 | files = ( 216 | ); 217 | inputPaths = ( 218 | "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", 219 | ); 220 | name = "Thin Binary"; 221 | outputPaths = ( 222 | ); 223 | runOnlyForDeploymentPostprocessing = 0; 224 | shellPath = /bin/sh; 225 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 226 | }; 227 | 47F5A62ADCF321E3D18E1DED /* [CP] Check Pods Manifest.lock */ = { 228 | isa = PBXShellScriptBuildPhase; 229 | buildActionMask = 2147483647; 230 | files = ( 231 | ); 232 | inputFileListPaths = ( 233 | ); 234 | inputPaths = ( 235 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 236 | "${PODS_ROOT}/Manifest.lock", 237 | ); 238 | name = "[CP] Check Pods Manifest.lock"; 239 | outputFileListPaths = ( 240 | ); 241 | outputPaths = ( 242 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 243 | ); 244 | runOnlyForDeploymentPostprocessing = 0; 245 | shellPath = /bin/sh; 246 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 247 | showEnvVarsInLog = 0; 248 | }; 249 | 9740EEB61CF901F6004384FC /* Run Script */ = { 250 | isa = PBXShellScriptBuildPhase; 251 | alwaysOutOfDate = 1; 252 | buildActionMask = 2147483647; 253 | files = ( 254 | ); 255 | inputPaths = ( 256 | ); 257 | name = "Run Script"; 258 | outputPaths = ( 259 | ); 260 | runOnlyForDeploymentPostprocessing = 0; 261 | shellPath = /bin/sh; 262 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n"; 263 | }; 264 | DE45073DF0D19C85955D3576 /* [CP] Embed Pods Frameworks */ = { 265 | isa = PBXShellScriptBuildPhase; 266 | buildActionMask = 2147483647; 267 | files = ( 268 | ); 269 | inputPaths = ( 270 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", 271 | "${BUILT_PRODUCTS_DIR}/ZIPFoundation/ZIPFoundation.framework", 272 | "${BUILT_PRODUCTS_DIR}/flutter_archive/flutter_archive.framework", 273 | ); 274 | name = "[CP] Embed Pods Frameworks"; 275 | outputPaths = ( 276 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ZIPFoundation.framework", 277 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_archive.framework", 278 | ); 279 | runOnlyForDeploymentPostprocessing = 0; 280 | shellPath = /bin/sh; 281 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; 282 | showEnvVarsInLog = 0; 283 | }; 284 | /* End PBXShellScriptBuildPhase section */ 285 | 286 | /* Begin PBXSourcesBuildPhase section */ 287 | 97C146EA1CF9000F007C117D /* Sources */ = { 288 | isa = PBXSourcesBuildPhase; 289 | buildActionMask = 2147483647; 290 | files = ( 291 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 292 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 293 | ); 294 | runOnlyForDeploymentPostprocessing = 0; 295 | }; 296 | /* End PBXSourcesBuildPhase section */ 297 | 298 | /* Begin PBXVariantGroup section */ 299 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 300 | isa = PBXVariantGroup; 301 | children = ( 302 | 97C146FB1CF9000F007C117D /* Base */, 303 | ); 304 | name = Main.storyboard; 305 | sourceTree = ""; 306 | }; 307 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 308 | isa = PBXVariantGroup; 309 | children = ( 310 | 97C147001CF9000F007C117D /* Base */, 311 | ); 312 | name = LaunchScreen.storyboard; 313 | sourceTree = ""; 314 | }; 315 | /* End PBXVariantGroup section */ 316 | 317 | /* Begin XCBuildConfiguration section */ 318 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 319 | isa = XCBuildConfiguration; 320 | baseConfigurationReference = 7BF65B94ADA84A925396EB4A /* Pods-Runner.profile.xcconfig */; 321 | buildSettings = { 322 | ALWAYS_SEARCH_USER_PATHS = NO; 323 | CLANG_ANALYZER_NONNULL = YES; 324 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 325 | CLANG_CXX_LIBRARY = "libc++"; 326 | CLANG_ENABLE_MODULES = YES; 327 | CLANG_ENABLE_OBJC_ARC = YES; 328 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 329 | CLANG_WARN_BOOL_CONVERSION = YES; 330 | CLANG_WARN_COMMA = YES; 331 | CLANG_WARN_CONSTANT_CONVERSION = YES; 332 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 333 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 334 | CLANG_WARN_EMPTY_BODY = YES; 335 | CLANG_WARN_ENUM_CONVERSION = YES; 336 | CLANG_WARN_INFINITE_RECURSION = YES; 337 | CLANG_WARN_INT_CONVERSION = YES; 338 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 339 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 340 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 341 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 342 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 343 | CLANG_WARN_STRICT_PROTOTYPES = YES; 344 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 345 | CLANG_WARN_UNREACHABLE_CODE = YES; 346 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 347 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 348 | COPY_PHASE_STRIP = NO; 349 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 350 | ENABLE_NS_ASSERTIONS = NO; 351 | ENABLE_STRICT_OBJC_MSGSEND = YES; 352 | GCC_C_LANGUAGE_STANDARD = gnu99; 353 | GCC_NO_COMMON_BLOCKS = YES; 354 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 355 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 356 | GCC_WARN_UNDECLARED_SELECTOR = YES; 357 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 358 | GCC_WARN_UNUSED_FUNCTION = YES; 359 | GCC_WARN_UNUSED_VARIABLE = YES; 360 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 361 | MTL_ENABLE_DEBUG_INFO = NO; 362 | SDKROOT = iphoneos; 363 | TARGETED_DEVICE_FAMILY = "1,2"; 364 | VALIDATE_PRODUCT = YES; 365 | }; 366 | name = Profile; 367 | }; 368 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 369 | isa = XCBuildConfiguration; 370 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 371 | buildSettings = { 372 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 373 | CLANG_ENABLE_MODULES = YES; 374 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 375 | DEVELOPMENT_TEAM = YOUR_TEAM_ID; 376 | ENABLE_BITCODE = NO; 377 | FRAMEWORK_SEARCH_PATHS = ( 378 | "$(inherited)", 379 | "$(PROJECT_DIR)/Flutter", 380 | ); 381 | INFOPLIST_FILE = Runner/Info.plist; 382 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 383 | LIBRARY_SEARCH_PATHS = ( 384 | "$(inherited)", 385 | "$(PROJECT_DIR)/Flutter", 386 | ); 387 | PRODUCT_BUNDLE_IDENTIFIER = com.kineapps.flutterArchiveExample; 388 | PRODUCT_NAME = "$(TARGET_NAME)"; 389 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 390 | SWIFT_VERSION = 5.0; 391 | VERSIONING_SYSTEM = "apple-generic"; 392 | }; 393 | name = Profile; 394 | }; 395 | 97C147031CF9000F007C117D /* Debug */ = { 396 | isa = XCBuildConfiguration; 397 | baseConfigurationReference = 6C8F778387C8B87CADE0DDD9 /* Pods-Runner.debug.xcconfig */; 398 | buildSettings = { 399 | ALWAYS_SEARCH_USER_PATHS = NO; 400 | CLANG_ANALYZER_NONNULL = YES; 401 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 402 | CLANG_CXX_LIBRARY = "libc++"; 403 | CLANG_ENABLE_MODULES = YES; 404 | CLANG_ENABLE_OBJC_ARC = YES; 405 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 406 | CLANG_WARN_BOOL_CONVERSION = YES; 407 | CLANG_WARN_COMMA = YES; 408 | CLANG_WARN_CONSTANT_CONVERSION = YES; 409 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 410 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 411 | CLANG_WARN_EMPTY_BODY = YES; 412 | CLANG_WARN_ENUM_CONVERSION = YES; 413 | CLANG_WARN_INFINITE_RECURSION = YES; 414 | CLANG_WARN_INT_CONVERSION = YES; 415 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 416 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 417 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 418 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 419 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 420 | CLANG_WARN_STRICT_PROTOTYPES = YES; 421 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 422 | CLANG_WARN_UNREACHABLE_CODE = YES; 423 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 424 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 425 | COPY_PHASE_STRIP = NO; 426 | DEBUG_INFORMATION_FORMAT = dwarf; 427 | ENABLE_STRICT_OBJC_MSGSEND = YES; 428 | ENABLE_TESTABILITY = YES; 429 | GCC_C_LANGUAGE_STANDARD = gnu99; 430 | GCC_DYNAMIC_NO_PIC = NO; 431 | GCC_NO_COMMON_BLOCKS = YES; 432 | GCC_OPTIMIZATION_LEVEL = 0; 433 | GCC_PREPROCESSOR_DEFINITIONS = ( 434 | "DEBUG=1", 435 | "$(inherited)", 436 | ); 437 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 438 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 439 | GCC_WARN_UNDECLARED_SELECTOR = YES; 440 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 441 | GCC_WARN_UNUSED_FUNCTION = YES; 442 | GCC_WARN_UNUSED_VARIABLE = YES; 443 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 444 | MTL_ENABLE_DEBUG_INFO = YES; 445 | ONLY_ACTIVE_ARCH = YES; 446 | SDKROOT = iphoneos; 447 | TARGETED_DEVICE_FAMILY = "1,2"; 448 | }; 449 | name = Debug; 450 | }; 451 | 97C147041CF9000F007C117D /* Release */ = { 452 | isa = XCBuildConfiguration; 453 | baseConfigurationReference = CE6E4F333B1E1EEE26EB0103 /* Pods-Runner.release.xcconfig */; 454 | buildSettings = { 455 | ALWAYS_SEARCH_USER_PATHS = NO; 456 | CLANG_ANALYZER_NONNULL = YES; 457 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 458 | CLANG_CXX_LIBRARY = "libc++"; 459 | CLANG_ENABLE_MODULES = YES; 460 | CLANG_ENABLE_OBJC_ARC = YES; 461 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 462 | CLANG_WARN_BOOL_CONVERSION = YES; 463 | CLANG_WARN_COMMA = YES; 464 | CLANG_WARN_CONSTANT_CONVERSION = YES; 465 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 466 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 467 | CLANG_WARN_EMPTY_BODY = YES; 468 | CLANG_WARN_ENUM_CONVERSION = YES; 469 | CLANG_WARN_INFINITE_RECURSION = YES; 470 | CLANG_WARN_INT_CONVERSION = YES; 471 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 472 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 473 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 474 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 475 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 476 | CLANG_WARN_STRICT_PROTOTYPES = YES; 477 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 478 | CLANG_WARN_UNREACHABLE_CODE = YES; 479 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 480 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 481 | COPY_PHASE_STRIP = NO; 482 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 483 | ENABLE_NS_ASSERTIONS = NO; 484 | ENABLE_STRICT_OBJC_MSGSEND = YES; 485 | GCC_C_LANGUAGE_STANDARD = gnu99; 486 | GCC_NO_COMMON_BLOCKS = YES; 487 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 488 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 489 | GCC_WARN_UNDECLARED_SELECTOR = YES; 490 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 491 | GCC_WARN_UNUSED_FUNCTION = YES; 492 | GCC_WARN_UNUSED_VARIABLE = YES; 493 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 494 | MTL_ENABLE_DEBUG_INFO = NO; 495 | SDKROOT = iphoneos; 496 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 497 | TARGETED_DEVICE_FAMILY = "1,2"; 498 | VALIDATE_PRODUCT = YES; 499 | }; 500 | name = Release; 501 | }; 502 | 97C147061CF9000F007C117D /* Debug */ = { 503 | isa = XCBuildConfiguration; 504 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 505 | buildSettings = { 506 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 507 | CLANG_ENABLE_MODULES = YES; 508 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 509 | DEVELOPMENT_TEAM = YOUR_TEAM_ID; 510 | ENABLE_BITCODE = NO; 511 | FRAMEWORK_SEARCH_PATHS = ( 512 | "$(inherited)", 513 | "$(PROJECT_DIR)/Flutter", 514 | ); 515 | INFOPLIST_FILE = Runner/Info.plist; 516 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 517 | LIBRARY_SEARCH_PATHS = ( 518 | "$(inherited)", 519 | "$(PROJECT_DIR)/Flutter", 520 | ); 521 | PRODUCT_BUNDLE_IDENTIFIER = com.kineapps.flutterArchiveExample; 522 | PRODUCT_NAME = "$(TARGET_NAME)"; 523 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 524 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 525 | SWIFT_VERSION = 5.0; 526 | VERSIONING_SYSTEM = "apple-generic"; 527 | }; 528 | name = Debug; 529 | }; 530 | 97C147071CF9000F007C117D /* Release */ = { 531 | isa = XCBuildConfiguration; 532 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 533 | buildSettings = { 534 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 535 | CLANG_ENABLE_MODULES = YES; 536 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 537 | DEVELOPMENT_TEAM = YOUR_TEAM_ID; 538 | ENABLE_BITCODE = NO; 539 | FRAMEWORK_SEARCH_PATHS = ( 540 | "$(inherited)", 541 | "$(PROJECT_DIR)/Flutter", 542 | ); 543 | INFOPLIST_FILE = Runner/Info.plist; 544 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 545 | LIBRARY_SEARCH_PATHS = ( 546 | "$(inherited)", 547 | "$(PROJECT_DIR)/Flutter", 548 | ); 549 | PRODUCT_BUNDLE_IDENTIFIER = com.kineapps.flutterArchiveExample; 550 | PRODUCT_NAME = "$(TARGET_NAME)"; 551 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 552 | SWIFT_VERSION = 5.0; 553 | VERSIONING_SYSTEM = "apple-generic"; 554 | }; 555 | name = Release; 556 | }; 557 | /* End XCBuildConfiguration section */ 558 | 559 | /* Begin XCConfigurationList section */ 560 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 561 | isa = XCConfigurationList; 562 | buildConfigurations = ( 563 | 97C147031CF9000F007C117D /* Debug */, 564 | 97C147041CF9000F007C117D /* Release */, 565 | 249021D3217E4FDB00AE95B9 /* Profile */, 566 | ); 567 | defaultConfigurationIsVisible = 0; 568 | defaultConfigurationName = Release; 569 | }; 570 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 571 | isa = XCConfigurationList; 572 | buildConfigurations = ( 573 | 97C147061CF9000F007C117D /* Debug */, 574 | 97C147071CF9000F007C117D /* Release */, 575 | 249021D4217E4FDB00AE95B9 /* Profile */, 576 | ); 577 | defaultConfigurationIsVisible = 0; 578 | defaultConfigurationName = Release; 579 | }; 580 | /* End XCConfigurationList section */ 581 | }; 582 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 583 | } 584 | -------------------------------------------------------------------------------- /example/macos/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 54; 7 | objects = { 8 | 9 | /* Begin PBXAggregateTarget section */ 10 | 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { 11 | isa = PBXAggregateTarget; 12 | buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; 13 | buildPhases = ( 14 | 33CC111E2044C6BF0003C045 /* ShellScript */, 15 | ); 16 | dependencies = ( 17 | ); 18 | name = "Flutter Assemble"; 19 | productName = FLX; 20 | }; 21 | /* End PBXAggregateTarget section */ 22 | 23 | /* Begin PBXBuildFile section */ 24 | 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; 25 | 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; 26 | 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 27 | 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 28 | 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; 29 | 63BDF32641D5531E2AC85C98 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 934DCDBF1E617308CA051283 /* Pods_Runner.framework */; }; 30 | /* End PBXBuildFile section */ 31 | 32 | /* Begin PBXContainerItemProxy section */ 33 | 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { 34 | isa = PBXContainerItemProxy; 35 | containerPortal = 33CC10E52044A3C60003C045 /* Project object */; 36 | proxyType = 1; 37 | remoteGlobalIDString = 33CC111A2044C6BA0003C045; 38 | remoteInfo = FLX; 39 | }; 40 | /* End PBXContainerItemProxy section */ 41 | 42 | /* Begin PBXCopyFilesBuildPhase section */ 43 | 33CC110E2044A8840003C045 /* Bundle Framework */ = { 44 | isa = PBXCopyFilesBuildPhase; 45 | buildActionMask = 2147483647; 46 | dstPath = ""; 47 | dstSubfolderSpec = 10; 48 | files = ( 49 | ); 50 | name = "Bundle Framework"; 51 | runOnlyForDeploymentPostprocessing = 0; 52 | }; 53 | /* End PBXCopyFilesBuildPhase section */ 54 | 55 | /* Begin PBXFileReference section */ 56 | 1ECEF6E2F16647E08B5C49B0 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 57 | 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 58 | 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; 59 | 33CC10ED2044A3C60003C045 /* flutter_archive_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = flutter_archive_example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 60 | 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 61 | 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 62 | 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 63 | 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; 64 | 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; 65 | 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; 66 | 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; 67 | 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; 68 | 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 69 | 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 70 | 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; 71 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; 72 | 934DCDBF1E617308CA051283 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 73 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; 74 | AA118D27FC678A676366C46F /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 75 | FD8F94FFCF840A8D20F8C02B /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 76 | /* End PBXFileReference section */ 77 | 78 | /* Begin PBXFrameworksBuildPhase section */ 79 | 33CC10EA2044A3C60003C045 /* Frameworks */ = { 80 | isa = PBXFrameworksBuildPhase; 81 | buildActionMask = 2147483647; 82 | files = ( 83 | 63BDF32641D5531E2AC85C98 /* Pods_Runner.framework in Frameworks */, 84 | ); 85 | runOnlyForDeploymentPostprocessing = 0; 86 | }; 87 | /* End PBXFrameworksBuildPhase section */ 88 | 89 | /* Begin PBXGroup section */ 90 | 119A99D3FFEE91AEDAE6CDFE /* Pods */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | 1ECEF6E2F16647E08B5C49B0 /* Pods-Runner.debug.xcconfig */, 94 | AA118D27FC678A676366C46F /* Pods-Runner.release.xcconfig */, 95 | FD8F94FFCF840A8D20F8C02B /* Pods-Runner.profile.xcconfig */, 96 | ); 97 | name = Pods; 98 | path = Pods; 99 | sourceTree = ""; 100 | }; 101 | 33BA886A226E78AF003329D5 /* Configs */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | 33E5194F232828860026EE4D /* AppInfo.xcconfig */, 105 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 106 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 107 | 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, 108 | ); 109 | path = Configs; 110 | sourceTree = ""; 111 | }; 112 | 33CC10E42044A3C60003C045 = { 113 | isa = PBXGroup; 114 | children = ( 115 | 33FAB671232836740065AC1E /* Runner */, 116 | 33CEB47122A05771004F2AC0 /* Flutter */, 117 | 33CC10EE2044A3C60003C045 /* Products */, 118 | D73912EC22F37F3D000D13A0 /* Frameworks */, 119 | 119A99D3FFEE91AEDAE6CDFE /* Pods */, 120 | ); 121 | sourceTree = ""; 122 | }; 123 | 33CC10EE2044A3C60003C045 /* Products */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | 33CC10ED2044A3C60003C045 /* flutter_archive_example.app */, 127 | ); 128 | name = Products; 129 | sourceTree = ""; 130 | }; 131 | 33CC11242044D66E0003C045 /* Resources */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | 33CC10F22044A3C60003C045 /* Assets.xcassets */, 135 | 33CC10F42044A3C60003C045 /* MainMenu.xib */, 136 | 33CC10F72044A3C60003C045 /* Info.plist */, 137 | ); 138 | name = Resources; 139 | path = ..; 140 | sourceTree = ""; 141 | }; 142 | 33CEB47122A05771004F2AC0 /* Flutter */ = { 143 | isa = PBXGroup; 144 | children = ( 145 | 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, 146 | 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, 147 | 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, 148 | 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, 149 | ); 150 | path = Flutter; 151 | sourceTree = ""; 152 | }; 153 | 33FAB671232836740065AC1E /* Runner */ = { 154 | isa = PBXGroup; 155 | children = ( 156 | 33CC10F02044A3C60003C045 /* AppDelegate.swift */, 157 | 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, 158 | 33E51913231747F40026EE4D /* DebugProfile.entitlements */, 159 | 33E51914231749380026EE4D /* Release.entitlements */, 160 | 33CC11242044D66E0003C045 /* Resources */, 161 | 33BA886A226E78AF003329D5 /* Configs */, 162 | ); 163 | path = Runner; 164 | sourceTree = ""; 165 | }; 166 | D73912EC22F37F3D000D13A0 /* Frameworks */ = { 167 | isa = PBXGroup; 168 | children = ( 169 | 934DCDBF1E617308CA051283 /* Pods_Runner.framework */, 170 | ); 171 | name = Frameworks; 172 | sourceTree = ""; 173 | }; 174 | /* End PBXGroup section */ 175 | 176 | /* Begin PBXNativeTarget section */ 177 | 33CC10EC2044A3C60003C045 /* Runner */ = { 178 | isa = PBXNativeTarget; 179 | buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; 180 | buildPhases = ( 181 | FC41AE4F95FDD64C1B1364BB /* [CP] Check Pods Manifest.lock */, 182 | 33CC10E92044A3C60003C045 /* Sources */, 183 | 33CC10EA2044A3C60003C045 /* Frameworks */, 184 | 33CC10EB2044A3C60003C045 /* Resources */, 185 | 33CC110E2044A8840003C045 /* Bundle Framework */, 186 | 3399D490228B24CF009A79C7 /* ShellScript */, 187 | 062BABA8F06F9299CDFDF8C5 /* [CP] Embed Pods Frameworks */, 188 | ); 189 | buildRules = ( 190 | ); 191 | dependencies = ( 192 | 33CC11202044C79F0003C045 /* PBXTargetDependency */, 193 | ); 194 | name = Runner; 195 | productName = Runner; 196 | productReference = 33CC10ED2044A3C60003C045 /* flutter_archive_example.app */; 197 | productType = "com.apple.product-type.application"; 198 | }; 199 | /* End PBXNativeTarget section */ 200 | 201 | /* Begin PBXProject section */ 202 | 33CC10E52044A3C60003C045 /* Project object */ = { 203 | isa = PBXProject; 204 | attributes = { 205 | LastSwiftUpdateCheck = 0920; 206 | LastUpgradeCheck = 1430; 207 | ORGANIZATIONNAME = "The Flutter Authors"; 208 | TargetAttributes = { 209 | 33CC10EC2044A3C60003C045 = { 210 | CreatedOnToolsVersion = 9.2; 211 | LastSwiftMigration = 1100; 212 | ProvisioningStyle = Automatic; 213 | SystemCapabilities = { 214 | com.apple.Sandbox = { 215 | enabled = 1; 216 | }; 217 | }; 218 | }; 219 | 33CC111A2044C6BA0003C045 = { 220 | CreatedOnToolsVersion = 9.2; 221 | ProvisioningStyle = Manual; 222 | }; 223 | }; 224 | }; 225 | buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; 226 | compatibilityVersion = "Xcode 8.0"; 227 | developmentRegion = en; 228 | hasScannedForEncodings = 0; 229 | knownRegions = ( 230 | en, 231 | Base, 232 | ); 233 | mainGroup = 33CC10E42044A3C60003C045; 234 | productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; 235 | projectDirPath = ""; 236 | projectRoot = ""; 237 | targets = ( 238 | 33CC10EC2044A3C60003C045 /* Runner */, 239 | 33CC111A2044C6BA0003C045 /* Flutter Assemble */, 240 | ); 241 | }; 242 | /* End PBXProject section */ 243 | 244 | /* Begin PBXResourcesBuildPhase section */ 245 | 33CC10EB2044A3C60003C045 /* Resources */ = { 246 | isa = PBXResourcesBuildPhase; 247 | buildActionMask = 2147483647; 248 | files = ( 249 | 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, 250 | 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, 251 | ); 252 | runOnlyForDeploymentPostprocessing = 0; 253 | }; 254 | /* End PBXResourcesBuildPhase section */ 255 | 256 | /* Begin PBXShellScriptBuildPhase section */ 257 | 062BABA8F06F9299CDFDF8C5 /* [CP] Embed Pods Frameworks */ = { 258 | isa = PBXShellScriptBuildPhase; 259 | buildActionMask = 2147483647; 260 | files = ( 261 | ); 262 | inputFileListPaths = ( 263 | ); 264 | name = "[CP] Embed Pods Frameworks"; 265 | outputFileListPaths = ( 266 | ); 267 | runOnlyForDeploymentPostprocessing = 0; 268 | shellPath = /bin/sh; 269 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; 270 | showEnvVarsInLog = 0; 271 | }; 272 | 3399D490228B24CF009A79C7 /* ShellScript */ = { 273 | isa = PBXShellScriptBuildPhase; 274 | alwaysOutOfDate = 1; 275 | buildActionMask = 2147483647; 276 | files = ( 277 | ); 278 | inputFileListPaths = ( 279 | ); 280 | inputPaths = ( 281 | ); 282 | outputFileListPaths = ( 283 | ); 284 | outputPaths = ( 285 | ); 286 | runOnlyForDeploymentPostprocessing = 0; 287 | shellPath = /bin/sh; 288 | shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; 289 | }; 290 | 33CC111E2044C6BF0003C045 /* ShellScript */ = { 291 | isa = PBXShellScriptBuildPhase; 292 | buildActionMask = 2147483647; 293 | files = ( 294 | ); 295 | inputFileListPaths = ( 296 | Flutter/ephemeral/FlutterInputs.xcfilelist, 297 | ); 298 | inputPaths = ( 299 | Flutter/ephemeral/tripwire, 300 | ); 301 | outputFileListPaths = ( 302 | Flutter/ephemeral/FlutterOutputs.xcfilelist, 303 | ); 304 | outputPaths = ( 305 | ); 306 | runOnlyForDeploymentPostprocessing = 0; 307 | shellPath = /bin/sh; 308 | shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; 309 | }; 310 | FC41AE4F95FDD64C1B1364BB /* [CP] Check Pods Manifest.lock */ = { 311 | isa = PBXShellScriptBuildPhase; 312 | buildActionMask = 2147483647; 313 | files = ( 314 | ); 315 | inputFileListPaths = ( 316 | ); 317 | inputPaths = ( 318 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 319 | "${PODS_ROOT}/Manifest.lock", 320 | ); 321 | name = "[CP] Check Pods Manifest.lock"; 322 | outputFileListPaths = ( 323 | ); 324 | outputPaths = ( 325 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 326 | ); 327 | runOnlyForDeploymentPostprocessing = 0; 328 | shellPath = /bin/sh; 329 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 330 | showEnvVarsInLog = 0; 331 | }; 332 | /* End PBXShellScriptBuildPhase section */ 333 | 334 | /* Begin PBXSourcesBuildPhase section */ 335 | 33CC10E92044A3C60003C045 /* Sources */ = { 336 | isa = PBXSourcesBuildPhase; 337 | buildActionMask = 2147483647; 338 | files = ( 339 | 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, 340 | 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, 341 | 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, 342 | ); 343 | runOnlyForDeploymentPostprocessing = 0; 344 | }; 345 | /* End PBXSourcesBuildPhase section */ 346 | 347 | /* Begin PBXTargetDependency section */ 348 | 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { 349 | isa = PBXTargetDependency; 350 | target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; 351 | targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; 352 | }; 353 | /* End PBXTargetDependency section */ 354 | 355 | /* Begin PBXVariantGroup section */ 356 | 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { 357 | isa = PBXVariantGroup; 358 | children = ( 359 | 33CC10F52044A3C60003C045 /* Base */, 360 | ); 361 | name = MainMenu.xib; 362 | path = Runner; 363 | sourceTree = ""; 364 | }; 365 | /* End PBXVariantGroup section */ 366 | 367 | /* Begin XCBuildConfiguration section */ 368 | 338D0CE9231458BD00FA5F75 /* Profile */ = { 369 | isa = XCBuildConfiguration; 370 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 371 | buildSettings = { 372 | ALWAYS_SEARCH_USER_PATHS = NO; 373 | CLANG_ANALYZER_NONNULL = YES; 374 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 375 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 376 | CLANG_CXX_LIBRARY = "libc++"; 377 | CLANG_ENABLE_MODULES = YES; 378 | CLANG_ENABLE_OBJC_ARC = YES; 379 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 380 | CLANG_WARN_BOOL_CONVERSION = YES; 381 | CLANG_WARN_CONSTANT_CONVERSION = YES; 382 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 383 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 384 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 385 | CLANG_WARN_EMPTY_BODY = YES; 386 | CLANG_WARN_ENUM_CONVERSION = YES; 387 | CLANG_WARN_INFINITE_RECURSION = YES; 388 | CLANG_WARN_INT_CONVERSION = YES; 389 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 390 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 391 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 392 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 393 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 394 | CODE_SIGN_IDENTITY = "-"; 395 | COPY_PHASE_STRIP = NO; 396 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 397 | ENABLE_NS_ASSERTIONS = NO; 398 | ENABLE_STRICT_OBJC_MSGSEND = YES; 399 | GCC_C_LANGUAGE_STANDARD = gnu11; 400 | GCC_NO_COMMON_BLOCKS = YES; 401 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 402 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 403 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 404 | GCC_WARN_UNUSED_FUNCTION = YES; 405 | GCC_WARN_UNUSED_VARIABLE = YES; 406 | MACOSX_DEPLOYMENT_TARGET = 10.14; 407 | MTL_ENABLE_DEBUG_INFO = NO; 408 | SDKROOT = macosx; 409 | SWIFT_COMPILATION_MODE = wholemodule; 410 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 411 | }; 412 | name = Profile; 413 | }; 414 | 338D0CEA231458BD00FA5F75 /* Profile */ = { 415 | isa = XCBuildConfiguration; 416 | baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; 417 | buildSettings = { 418 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 419 | CLANG_ENABLE_MODULES = YES; 420 | CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; 421 | CODE_SIGN_STYLE = Automatic; 422 | COMBINE_HIDPI_IMAGES = YES; 423 | FRAMEWORK_SEARCH_PATHS = ( 424 | "$(inherited)", 425 | "$(PROJECT_DIR)/Flutter/ephemeral", 426 | ); 427 | INFOPLIST_FILE = Runner/Info.plist; 428 | LD_RUNPATH_SEARCH_PATHS = ( 429 | "$(inherited)", 430 | "@executable_path/../Frameworks", 431 | ); 432 | PROVISIONING_PROFILE_SPECIFIER = ""; 433 | SWIFT_VERSION = 5.0; 434 | }; 435 | name = Profile; 436 | }; 437 | 338D0CEB231458BD00FA5F75 /* Profile */ = { 438 | isa = XCBuildConfiguration; 439 | buildSettings = { 440 | CODE_SIGN_STYLE = Manual; 441 | PRODUCT_NAME = "$(TARGET_NAME)"; 442 | }; 443 | name = Profile; 444 | }; 445 | 33CC10F92044A3C60003C045 /* Debug */ = { 446 | isa = XCBuildConfiguration; 447 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 448 | buildSettings = { 449 | ALWAYS_SEARCH_USER_PATHS = NO; 450 | CLANG_ANALYZER_NONNULL = YES; 451 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 452 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 453 | CLANG_CXX_LIBRARY = "libc++"; 454 | CLANG_ENABLE_MODULES = YES; 455 | CLANG_ENABLE_OBJC_ARC = YES; 456 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 457 | CLANG_WARN_BOOL_CONVERSION = YES; 458 | CLANG_WARN_CONSTANT_CONVERSION = YES; 459 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 460 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 461 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 462 | CLANG_WARN_EMPTY_BODY = YES; 463 | CLANG_WARN_ENUM_CONVERSION = YES; 464 | CLANG_WARN_INFINITE_RECURSION = YES; 465 | CLANG_WARN_INT_CONVERSION = YES; 466 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 467 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 468 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 469 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 470 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 471 | CODE_SIGN_IDENTITY = "-"; 472 | COPY_PHASE_STRIP = NO; 473 | DEBUG_INFORMATION_FORMAT = dwarf; 474 | ENABLE_STRICT_OBJC_MSGSEND = YES; 475 | ENABLE_TESTABILITY = YES; 476 | GCC_C_LANGUAGE_STANDARD = gnu11; 477 | GCC_DYNAMIC_NO_PIC = NO; 478 | GCC_NO_COMMON_BLOCKS = YES; 479 | GCC_OPTIMIZATION_LEVEL = 0; 480 | GCC_PREPROCESSOR_DEFINITIONS = ( 481 | "DEBUG=1", 482 | "$(inherited)", 483 | ); 484 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 485 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 486 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 487 | GCC_WARN_UNUSED_FUNCTION = YES; 488 | GCC_WARN_UNUSED_VARIABLE = YES; 489 | MACOSX_DEPLOYMENT_TARGET = 10.14; 490 | MTL_ENABLE_DEBUG_INFO = YES; 491 | ONLY_ACTIVE_ARCH = YES; 492 | SDKROOT = macosx; 493 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 494 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 495 | }; 496 | name = Debug; 497 | }; 498 | 33CC10FA2044A3C60003C045 /* Release */ = { 499 | isa = XCBuildConfiguration; 500 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 501 | buildSettings = { 502 | ALWAYS_SEARCH_USER_PATHS = NO; 503 | CLANG_ANALYZER_NONNULL = YES; 504 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 505 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 506 | CLANG_CXX_LIBRARY = "libc++"; 507 | CLANG_ENABLE_MODULES = YES; 508 | CLANG_ENABLE_OBJC_ARC = YES; 509 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 510 | CLANG_WARN_BOOL_CONVERSION = YES; 511 | CLANG_WARN_CONSTANT_CONVERSION = YES; 512 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 513 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 514 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 515 | CLANG_WARN_EMPTY_BODY = YES; 516 | CLANG_WARN_ENUM_CONVERSION = YES; 517 | CLANG_WARN_INFINITE_RECURSION = YES; 518 | CLANG_WARN_INT_CONVERSION = YES; 519 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 520 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 521 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 522 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 523 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 524 | CODE_SIGN_IDENTITY = "-"; 525 | COPY_PHASE_STRIP = NO; 526 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 527 | ENABLE_NS_ASSERTIONS = NO; 528 | ENABLE_STRICT_OBJC_MSGSEND = YES; 529 | GCC_C_LANGUAGE_STANDARD = gnu11; 530 | GCC_NO_COMMON_BLOCKS = YES; 531 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 532 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 533 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 534 | GCC_WARN_UNUSED_FUNCTION = YES; 535 | GCC_WARN_UNUSED_VARIABLE = YES; 536 | MACOSX_DEPLOYMENT_TARGET = 10.14; 537 | MTL_ENABLE_DEBUG_INFO = NO; 538 | SDKROOT = macosx; 539 | SWIFT_COMPILATION_MODE = wholemodule; 540 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 541 | }; 542 | name = Release; 543 | }; 544 | 33CC10FC2044A3C60003C045 /* Debug */ = { 545 | isa = XCBuildConfiguration; 546 | baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; 547 | buildSettings = { 548 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 549 | CLANG_ENABLE_MODULES = YES; 550 | CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; 551 | CODE_SIGN_STYLE = Automatic; 552 | COMBINE_HIDPI_IMAGES = YES; 553 | FRAMEWORK_SEARCH_PATHS = ( 554 | "$(inherited)", 555 | "$(PROJECT_DIR)/Flutter/ephemeral", 556 | ); 557 | INFOPLIST_FILE = Runner/Info.plist; 558 | LD_RUNPATH_SEARCH_PATHS = ( 559 | "$(inherited)", 560 | "@executable_path/../Frameworks", 561 | ); 562 | PROVISIONING_PROFILE_SPECIFIER = ""; 563 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 564 | SWIFT_VERSION = 5.0; 565 | }; 566 | name = Debug; 567 | }; 568 | 33CC10FD2044A3C60003C045 /* Release */ = { 569 | isa = XCBuildConfiguration; 570 | baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; 571 | buildSettings = { 572 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 573 | CLANG_ENABLE_MODULES = YES; 574 | CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; 575 | CODE_SIGN_STYLE = Automatic; 576 | COMBINE_HIDPI_IMAGES = YES; 577 | FRAMEWORK_SEARCH_PATHS = ( 578 | "$(inherited)", 579 | "$(PROJECT_DIR)/Flutter/ephemeral", 580 | ); 581 | INFOPLIST_FILE = Runner/Info.plist; 582 | LD_RUNPATH_SEARCH_PATHS = ( 583 | "$(inherited)", 584 | "@executable_path/../Frameworks", 585 | ); 586 | PROVISIONING_PROFILE_SPECIFIER = ""; 587 | SWIFT_VERSION = 5.0; 588 | }; 589 | name = Release; 590 | }; 591 | 33CC111C2044C6BA0003C045 /* Debug */ = { 592 | isa = XCBuildConfiguration; 593 | buildSettings = { 594 | CODE_SIGN_STYLE = Manual; 595 | PRODUCT_NAME = "$(TARGET_NAME)"; 596 | }; 597 | name = Debug; 598 | }; 599 | 33CC111D2044C6BA0003C045 /* Release */ = { 600 | isa = XCBuildConfiguration; 601 | buildSettings = { 602 | CODE_SIGN_STYLE = Automatic; 603 | PRODUCT_NAME = "$(TARGET_NAME)"; 604 | }; 605 | name = Release; 606 | }; 607 | /* End XCBuildConfiguration section */ 608 | 609 | /* Begin XCConfigurationList section */ 610 | 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { 611 | isa = XCConfigurationList; 612 | buildConfigurations = ( 613 | 33CC10F92044A3C60003C045 /* Debug */, 614 | 33CC10FA2044A3C60003C045 /* Release */, 615 | 338D0CE9231458BD00FA5F75 /* Profile */, 616 | ); 617 | defaultConfigurationIsVisible = 0; 618 | defaultConfigurationName = Release; 619 | }; 620 | 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { 621 | isa = XCConfigurationList; 622 | buildConfigurations = ( 623 | 33CC10FC2044A3C60003C045 /* Debug */, 624 | 33CC10FD2044A3C60003C045 /* Release */, 625 | 338D0CEA231458BD00FA5F75 /* Profile */, 626 | ); 627 | defaultConfigurationIsVisible = 0; 628 | defaultConfigurationName = Release; 629 | }; 630 | 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { 631 | isa = XCConfigurationList; 632 | buildConfigurations = ( 633 | 33CC111C2044C6BA0003C045 /* Debug */, 634 | 33CC111D2044C6BA0003C045 /* Release */, 635 | 338D0CEB231458BD00FA5F75 /* Profile */, 636 | ); 637 | defaultConfigurationIsVisible = 0; 638 | defaultConfigurationName = Release; 639 | }; 640 | /* End XCConfigurationList section */ 641 | }; 642 | rootObject = 33CC10E52044A3C60003C045 /* Project object */; 643 | } 644 | --------------------------------------------------------------------------------