Accessing flutter assets with iOS swift code

1,547

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)
        }
Share:
1,547
Mohammad Amir
Author by

Mohammad Amir

Mobile application developer with 3 years of experience in developing applications in iOS and Android with Flutter.

Updated on December 13, 2022

Comments

  • Mohammad Amir
    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
    Paresh. P about 4 years
    I have made same implementation still not getting path. The path is nil
  • Paresh. P
    Paresh. P about 4 years
    Where have you created the Image folder?
  • Mohammad Amir
    Mohammad Amir about 4 years
    The images folder is inside the main project folder. in the same scope as lib, build, android and iOS folders.
  • Mohammad Amir
    Mohammad Amir about 4 years
    I've edited the answer and added a more complete example. You could check it out and see if it answers your question.
  • shield
    shield about 3 years
    If you need to access an image in another package, use the optional fromPackage parameter in the registrar?.lookupKey() call.
  • shield
    shield almost 3 years
    For those trying to do the same thing in an android plugin, look at this answer.