wip: add platform channels

This commit is contained in:
shenlong-tanwen 2024-09-15 03:31:01 +05:30
parent f1dcfbc594
commit 37b15869d5
9 changed files with 149 additions and 12 deletions

View File

@ -1,5 +1,15 @@
package com.alextran.immich
import ImmichHostService
import com.alextran.immich.platform.ImmichHostServiceImpl
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
class MainActivity: FlutterActivity()
class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
// Register piegon handler
ImmichHostService.setUp(flutterEngine.dartExecutor.binaryMessenger, ImmichHostServiceImpl())
}
}

View File

@ -0,0 +1,47 @@
package com.alextran.immich.platform
import ImmichHostService
import android.util.Log
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.io.FileInputStream
import java.security.MessageDigest
class ImmichHostServiceImpl: ImmichHostService {
@OptIn(DelicateCoroutinesApi::class)
override fun digestFiles(paths: List<String>, callback: (Result<List<ByteArray?>?>) -> Unit) {
GlobalScope.launch(Dispatchers.IO) {
val buf = ByteArray(Companion.BUFFER_SIZE)
val digest: MessageDigest = MessageDigest.getInstance("SHA-1")
val hashes = arrayOfNulls<ByteArray>(paths.size)
for (i in paths.indices) {
val path = paths[i]
var len = 0
try {
val file = FileInputStream(path)
file.use { assetFile ->
while (true) {
len = assetFile.read(buf)
if (len != Companion.BUFFER_SIZE) break
digest.update(buf)
}
}
digest.update(buf, 0, len)
hashes[i] = digest.digest()
} catch (e: Exception) {
// skip this file
Log.w(TAG, "Failed to hash file ${paths[i]}: $e")
}
}
callback(Result.success(hashes.asList()))
}
}
companion object {
private const val BUFFER_SIZE = 2 * 1024 * 1024;
private const val TAG = "ImmichHostServiceImpl"
}
}

View File

@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '12.0'
platform :ios, '13.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

View File

@ -83,6 +83,6 @@ SPEC CHECKSUMS:
sqlite3_flutter_libs: c00457ebd31e59fa6bb830380ddba24d44fbcd3b
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
PODFILE CHECKSUM: 64c9b5291666c0ca3caabdfe9865c141ac40321d
PODFILE CHECKSUM: 47bc0bc2c8210ec5b4886fa2f4d1046a536e3e17
COCOAPODS: 1.15.2

View File

@ -15,6 +15,8 @@
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
B2FE78A32C9633490065752A /* Messages.g.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2FE78A02C9633490065752A /* Messages.g.swift */; };
B2FE78A42C9633490065752A /* MessagesImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2FE78A12C9633490065752A /* MessagesImpl.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -60,6 +62,8 @@
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
B0875BFC00218C7E86E76B26 /* 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 = "<group>"; };
B2FE78A02C9633490065752A /* Messages.g.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Messages.g.swift; sourceTree = "<group>"; };
B2FE78A12C9633490065752A /* MessagesImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagesImpl.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -81,7 +85,6 @@
5743DC0B43F97DC290E40819 /* Pods-Runner.release.xcconfig */,
B0875BFC00218C7E86E76B26 /* Pods-Runner.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
@ -136,6 +139,7 @@
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
B2FE78A22C9633490065752A /* Platform */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
@ -148,6 +152,15 @@
path = Runner;
sourceTree = "<group>";
};
B2FE78A22C9633490065752A /* Platform */ = {
isa = PBXGroup;
children = (
B2FE78A02C9633490065752A /* Messages.g.swift */,
B2FE78A12C9633490065752A /* MessagesImpl.swift */,
);
path = Platform;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -197,7 +210,7 @@
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1510;
LastUpgradeCheck = 1540;
ORGANIZATIONNAME = "";
TargetAttributes = {
331C8080294A63A400263BE5 = {
@ -336,8 +349,10 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B2FE78A32C9633490065752A /* Messages.g.swift in Sources */,
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
B2FE78A42C9633490065752A /* MessagesImpl.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -395,6 +410,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -425,12 +441,12 @@
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
baseConfigurationReference = B0875BFC00218C7E86E76B26 /* Pods-Runner.profile.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 2F67MQ8R79;
DEVELOPMENT_TEAM = 7AM53GU2W3;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "immich-v2";
@ -498,6 +514,7 @@
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB31CF90195004384FC /* Generated.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
@ -520,6 +537,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -577,6 +595,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -609,12 +628,12 @@
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
baseConfigurationReference = 2DB7C9F14E5C41B0C29A9694 /* Pods-Runner.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 2F67MQ8R79;
DEVELOPMENT_TEAM = 7AM53GU2W3;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "immich-v2";
@ -636,12 +655,12 @@
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
baseConfigurationReference = 5743DC0B43F97DC290E40819 /* Pods-Runner.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 2F67MQ8R79;
DEVELOPMENT_TEAM = 7AM53GU2W3;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "immich-v2";

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
LastUpgradeVersion = "1540"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@ -8,6 +8,11 @@ import Flutter
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
// Register piegon handler
let controller: FlutterViewController = window?.rootViewController as! FlutterViewController
ImmichHostServiceSetup.setUp(binaryMessenger: controller.binaryMessenger, api: ImmichHostServiceImpl())
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}

View File

@ -0,0 +1,39 @@
import CryptoKit
class ImmichHostServiceImpl: ImmichHostService {
func digestFiles(paths: [String], completion: @escaping (Result<[FlutterStandardTypedData?]?, Error>) -> Void) {
let bufsize = 2 * 1024 * 1024
// Private error to throw if file cannot be read
enum DigestError: String, LocalizedError {
case NoFileHandle = "Cannot Open File Handle"
public var errorDescription: String? { self.rawValue }
}
// Compute hash in background thread
DispatchQueue.global(qos: .background).async {
var hashes: [FlutterStandardTypedData?] = Array(repeating: nil, count: paths.count)
for i in (0 ..< paths.count) {
do {
guard let file = FileHandle(forReadingAtPath: paths[i]) else { throw DigestError.NoFileHandle }
var hasher = Insecure.SHA1.init();
while autoreleasepool(invoking: {
let chunk = file.readData(ofLength: bufsize)
guard !chunk.isEmpty else { return false } // EOF
hasher.update(data: chunk)
return true // continue
}) { }
let digest = hasher.finalize()
hashes[i] = FlutterStandardTypedData(bytes: Data(Array(digest.makeIterator())))
} catch {
print("Cannot calculate the digest of the file \(paths[i]) due to \(error.localizedDescription)")
}
}
// Return result in main thread
DispatchQueue.main.async {
completion(.success(Array(hashes)))
}
}
}
}

View File

@ -0,0 +1,17 @@
// ignore: depend_on_referenced_packages
import 'package:pigeon/pigeon.dart';
@ConfigurePigeon(PigeonOptions(
dartOut: 'lib/platform/messages.g.dart',
dartOptions: DartOptions(),
kotlinOut:
'android/app/src/main/kotlin/com/alextran/immich/platform/Messages.g.kt',
kotlinOptions: KotlinOptions(),
swiftOut: 'ios/Runner/Platform/Messages.g.swift',
swiftOptions: SwiftOptions(),
))
@HostApi()
abstract class ImmichHostService {
@async
List<Uint8List?>? digestFiles(List<String> paths);
}