Printing on iOS using UIPrintInteractionController

Hello, I’m having trouble getting this view to display. I believe I have configured it correctly, and tested in a fresh iOS Objective-C app with something very similar.

The PrintManager is created as a global JS module.

using Uno;
using Uno.UX;
using Uno.Collections;
using Fuse;
using Fuse.Reactive;
using Fuse.Scripting;
using Fuse.Controls;
using Uno.Compiler.ExportTargetInterop;

[UXGlobalModule]
public class PrintManager : NativeModule
{
	static readonly PrintManager _instance;
	public PrintManager () {
		if(_instance != null) return;
		Uno.UX.Resource.SetGlobalKey(_instance = this, "PrintManager");

        AddMember(new NativeFunction("print", (NativeCallback)Print));

	}

    object Print(Context c, object[] args) {

        Fuse.Scripting.Array pages = args[0] as Fuse.Scripting.Array;
        for(int i = 0; i < pages.Length; ++i) {
            debug_log "Page " + i.ToString() + ": " + (pages[i] as string);
        }

        string jobName = "Print";
        if(args.Length > 1) {
            jobName = args[1] as string;
        }

        string[] pagesImpl = new string[pages.Length];
        for (var i = 0; i < pages.Length; i++) {
            pagesImpl[i] = pages[i] as string;
        }

        PrintImpl(pagesImpl, jobName);

        return null;
    }

    extern(!iOS) public void PrintImpl(string[] files, string jobName)
    {
        debug_log "Printing not supported yet.";
    }

    [Foreign(Language.ObjC)]
    extern(iOS) public void PrintImpl(string[] files, string jobName)
    @{
        if([UIPrintInteractionController isPrintingAvailable]){
            UIPrintInteractionController *printController = [UIPrintInteractionController sharedPrintController];
            UIPrintInfo*printInfo = [UIPrintInfo printInfo];
            [printInfo setOutputType:UIPrintInfoOutputGeneral];
            [printInfo setJobName:jobName];
            [printInfo setOrientation:UIPrintInfoOrientationPortrait];
            [printController setPrintInfo:printInfo];
            [printController setShowsNumberOfCopies:NO];
            [printController setShowsPageRange:NO];

            NSMutableArray * printItems = [NSMutableArray arrayWithCapacity:1];
            NSArray * orig = [files copyArray];
            for(id file in orig) {
                NSURL *baseURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"file:///%@", file]];
                NSLog(@"Will print: %@", baseURL.absoluteString);
                [printItems addObject:baseURL];
            }


            [printController setPrintingItems:printItems];
            [printController presentAnimated:YES completionHandler:^(UIPrintInteractionController *printInteractionController, BOOL completed, NSError *error2) {
                }];
        }
    @}

}

And this is called from JS using PrintManager.print(["array_of_files"]);.

I have verified that the images I’m trying to print are valid.

When this code is run, the UX becomes unresponsive (on an iPhone) until I click on the top left - (which is where the “Cancel” button is).

Small update - if I click on where the “Print” button would be, the printer prints the image. So I can confirm this is some kind of display issue on Fuse. Any help is appreciated.

Hi mitesh,

I am no Uno or foreign code specialist, but I’ll try to help. Based on your description, it seems that you’re not running on the UI thread, which could explain why the stuff is “invisible”.

Taking a look at Fuse.Share implementation on iOS, we see something like this:

UIActivityViewController* activityVC = [[UIActivityViewController alloc] initWithActivityItems:@[text] applicationActivities:nil];
dispatch_async(dispatch_get_main_queue(), ^{
	[[[[UIApplication sharedApplication] keyWindow] rootViewController] presentViewController:activityVC animated:YES completion:nil];
});

So maybe you can employ a similar tactic to get hold of the right thread?

Thank you!

So the problem was thread related and the clue was available in the code provided. I just had to change how I launched this print controller using the dispatch mechanism:

dispatch_async(dispatch_get_main_queue(), ^{

     [printController presentAnimated:NO completionHandler:^(UIPrintInteractionController *printInteractionController, BOOL completed, NSError *error2) {
     }];
                    
});