Accessing flutter assets with iOS swift code
So I've found the answer in Swift and it goes like this:
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "image_process_plugin", binaryMessenger: registrar.messenger())
let instance = SwiftImageProcessPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
//giving access to the plugin registrar and since it's static we can access variables from outer scope:
instance.registrar = registrar
}
in the outer scope(in the class defined, which in my case was SwiftImageProcessPlugin) I defined the registrar variable used in the scope for the instance variable:
var registrar: FlutterPluginRegistrar? = nil
and then used it to access my asset Image like this:
let key = registrar?.lookupKey(forAsset: "Images/topImage.png")
let topPath = Bundle.main.path(forResource: key, ofType: nil)!
let topImage: UIImage = UIImage(contentsOfFile: topPath)!
Complete example code for this part is like this:
@available(iOS 10.0, *)
public class SwiftImageProcessPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "image_process_plugin", binaryMessenger: registrar.messenger())
let instance = SwiftImageProcessPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
//giving access to the plugin registrar and since it's static we can access variables from outer scope:
instance.registrar = registrar
}
//defining registrar variable:
var registrar: FlutterPluginRegistrar? = nil
//handling the method:
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
//MARK: photo sharing
if call.method == "preparePhotoForSharing2"{
let values = call.arguments as! NSDictionary
preparePhotoForSharing2(result: result, values: values)
}
else {
result(FlutterMethodNotImplemented)
return
}
}
and the function:
@available(iOS 10.0, *)
func preparePhotoForSharing2(result: @escaping FlutterResult, values: NSDictionary){
DispatchQueue.global(qos: .userInitiated).async {
let srcPath: String = values["srcPath"] as! String
let destPath: String = values["destPath"] as! String
let assetImagePath: String = values["assetImagePath"] as! String
// setting source image and getting height and width:
let srcUrl: URL = URL(fileURLWithPath: srcPath)
let srcImage: UIImage = UIImage(contentsOfFile: srcUrl.path)!
let srcheightInPoints = srcImage.size.height
let srcheightInPixels = srcheightInPoints * srcImage.scale
let srcwidthInPoints = srcImage.size.width
let srcwidthInPixels = srcwidthInPoints * srcImage.scale
// setting asset image and getting height and width:
let key = self.registrar?.lookupKey(forAsset: assetImagePath)
let assetPath = Bundle.main.path(forResource: key, ofType: nil)!
let assetImage: UIImage = UIImage(contentsOfFile: assetPath)!
let assetheightInPoints = assetImage.size.height
let assetheightInPixels = assetheightInPoints * assetImage.scale
let assetwidthInPoints = assetImage.size.width
let assetwidthInPixels = assetwidthInPoints * assetImage.scale
let cWidth:Int = Int(assetwidthInPixels)
let _1Height:Int = Int(Double(assetwidthInPixels / srcwidthInPixels) * Double(srcheightInPixels));
let cHeight:Int = _1Height + Int(assetheightInPixels)
//starting to process the image:
let size = CGSize(width: cWidth, height: cHeight)
UIGraphicsBeginImageContext(size)
let areaSize = CGRect(x: 0, y: 0, width: cWidth, height: _1Height)
srcImage.draw(in: areaSize)
let areaSize2 = CGRect(x: 0, y: _1Height, width: cWidth, height: Int(assetheightInPixels))
assetImage.draw(in: areaSize2, blendMode: .normal, alpha: 1)
let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
let newUrl: URL = URL(fileURLWithPath: destPath)
//saving the new image to the given address
do{ try newImage.jpegData(compressionQuality: 1.0)?.write(to: newUrl)}
catch {
print(Error.self)
DispatchQueue.main.sync {
result("0")
}
}
// ending the image process
UIGraphicsEndImageContext()
DispatchQueue.main.sync {
result(nil)
}
Mohammad Amir
Mobile application developer with 3 years of experience in developing applications in iOS and Android with Flutter.
Updated on December 13, 2022Comments
-
Mohammad Amir over 1 year
I've written an iOS plugin in swift for flutter which I have to pass two images to it. I'm trying to access an Image from my flutter assets via swift Code.
I've checked the documents and there is only some code in objective-c for my problem. https://flutter.dev/docs/development/ui/assets-and-images#asset-variants
The code given in flutter documents is this:
NSString* key = [registrar lookupKeyForAsset:@"icons/heart.png"]; NSString* path = [[NSBundle mainBundle] pathForResource:key ofType:nil];
I want to get a URL to the image which could be accessible if the code above was in swift.
Similar to Is there a way to access Flutter resources from native code?
-
Paresh. P about 4 yearsI have made same implementation still not getting path. The path is nil
-
Paresh. P about 4 yearsWhere have you created the Image folder?
-
Mohammad Amir about 4 yearsThe images folder is inside the main project folder. in the same scope as lib, build, android and iOS folders.
-
Mohammad Amir about 4 yearsI've edited the answer and added a more complete example. You could check it out and see if it answers your question.
-
shield about 3 yearsIf you need to access an image in another package, use the optional
fromPackage
parameter in theregistrar?.lookupKey()
call. -
shield almost 3 yearsFor those trying to do the same thing in an android plugin, look at this answer.