Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support react-native-html-to-pdf #7723

Closed
2 tasks done
omdxp opened this issue May 4, 2021 · 23 comments
Closed
2 tasks done

Support react-native-html-to-pdf #7723

omdxp opened this issue May 4, 2021 · 23 comments
Labels
enhancement Extensions Tracks issues against community modules and extensions Recommend: Not Planned Recommend that issue should be given Not Planned milestone.
Milestone

Comments

@omdxp
Copy link

omdxp commented May 4, 2021

Support react-native-html-to-pdf on RNW

Basic Info

  • Module Repo URL: link to repo
  • Target version: ^0.63
  • Issue exists on module repo (if so, link)
  • Module has a Legacy/C# implementation (if so, link)

Which app/customer is requesting this module?

I need this module to work in order to create a pdf file that can be printed using another module (react-native-print) which has the option to print from a an existing pdf file and does not have the support to print an html string directly (which is supported in Android and iOS but not on Windows).

In what scenarios will this module be used?

The most useful scenario is to print custom documents that can be edited from React Native app. It will be a game changing 😄.

@omdxp omdxp added Extensions Tracks issues against community modules and extensions enhancement labels May 4, 2021
@ghost ghost added the Needs: Triage 🔍 New issue that needs to be reviewed by the issue management team (label applied by bot) label May 4, 2021
@asklar
Copy link
Member

asklar commented May 5, 2021

the linked legacy/C# implementation isn't usable:

  • it's not a react-native-windows legacy module
  • it uses WPF and .net core

the work here seems to be to either use the Windows.Data.Pdf APIs, or rather use a webview to print the pdf content (see e.g. this StackOverflow example)

@omdxp
Copy link
Author

omdxp commented May 5, 2021

@asklar thanks for the example, I'll check it out and let you know.

About that legacy module, I know it uses .Net Core and I thought since UWP uses .Net Standard. Is it possible to to have a .Net Standard project that reference that .Net Core module and can be referenced from the UWP project?

@asklar asklar removed the Needs: Triage 🔍 New issue that needs to be reviewed by the issue management team (label applied by bot) label May 6, 2021
@asklar asklar added this to the Backlog milestone May 6, 2021
@asklar
Copy link
Member

asklar commented May 6, 2021

It might be possible to just add this functionality into react-native-print instead, which would make more sense here.
CC @stmoy

@omdxp
Copy link
Author

omdxp commented May 6, 2021

Totally agree!

@Enragedsaturday
Copy link

@asklar I need the functionality of react-native-html-to-pdf (not the print part that op mentioned) to be able to implement RNW in a current project. Possibly a more appropriate legacy/C# implementation could be found here.

@omdxp
Copy link
Author

omdxp commented May 19, 2021

@Enragedsaturday I have used DinkToPdf and it does the job in debug, but when I tried to run the app in release build it throws an exception System.InvalidCastException: 'Specified cast is not valid.' which is BasicConverter.cs not found. I have copied the libwkhtmltox.dll and I have specified to copy to output directory as Copy Always but still it doesn't work in release. Do you have any idea how to solve that?

@Enragedsaturday
Copy link

Enragedsaturday commented May 20, 2021

@Omar-Belghaouti no clue, I haven't used the library. I just did some research and found that it looked like it was a more appropriate solution that @asklar was looking for. I'm hoping he can take a look.

@asklar
Copy link
Member

asklar commented May 20, 2021

that library seems to be .net core too; uwp apps (like react native apps) go through a cross-compilation from managed (IL) to native code called .net native, I've written on this somewhat here. For apps/libraries that get cross-compiled, reflection (incl. casts) doesn't work unless you do some extra work to tell the toolchain what types / namespaces to generate reflection information for. There is information online somewhere in the .net native docs site about "runtime directives" (rd.xml) and the syntax. Having said that there are no guarantees that this would work since the library was not compiled for uwp in the first place so your mileage may vary.

@Enragedsaturday
Copy link

@asklar thanks for looking into it. I am but a humble JS dev with no knowledge of the wizardry that goes into native modules. That being said if there is a solution for using react-native-html-to-pdf or something similar in rnw/rn, I would appreciate a push in the right direction.

@asklar
Copy link
Member

asklar commented May 20, 2021

I think for converting html to pdf (without the print to a physical printer part), you'd want to leverage the react-native-webview module which allows hosting the html, then print the content to the "Microsoft PDF printer" that is installed by default for everyone, which will save the file somewhere, and then you'd load that pdf from disk. This feels fairly cumbersome, so let me ask some folks and see if we can figure out a better solution.

@Enragedsaturday
Copy link

@asklar yeah tbh even this module on rn isn't ideal, as I'm sending the file to the cloud and it isn't just held in memory. At a minimum I would need access to the file location, and ideally a promise based system that I can use to determine the file has been saved successfully so I can send it to the database.

@omdxp
Copy link
Author

omdxp commented May 20, 2021

Thanks @asklar for looking into this. I thought about using webview and sending a JS script in the WebView component. However, I'm not sure if window.print() will work inside a the script tag as I tried with this code snippet:

...
<script>
     setTimout(function() {
          window.print();
          window.ReactNativeWebView.postMessage('Hello!');
     }, 2000);
</script>

And in the React Native part I did this:

<WebView
    source={{html: html}}
    onMessage={event => {
         alert(event.nativeEvent.data);
    }}
/>

I get only the alert that shows Hello! message. I was hoping that at least it'll show the window that shows a preview of the page like we do in the browsers Ctrl + P and then click on Print.

I think that wkhtmltopdf can be helpful if we find a way to work around it on a UWP project. DinkToPdf is wrapper that uses its dll.

@asklar
Copy link
Member

asklar commented May 21, 2021

WebView is just a web control, without the capabilities that a web browser would implement, like window.print, window.alert, etc. As it is, window.print won't work out of the box in react-native-webview; basically every window.foo functionality needs special handling, react-native-webview has a special case for window.alert but that's the only window function it knows how to handle.
There is work in WebView2 (which react-native-webview doesn't yet use), to have it support window.print out of the box.
MicrosoftEdge/WebView2Feedback#7

I looked at wkhtmltopdf briefly, it uses the QT WebKit engine to render the html, I am not familiar with what that entails or if that is possible to do. It sounds like DinkToPdf could be recompiled against the .net uwp framework and then add the right magic "runtime directives" so that the .net framework knows how to cast between types.

I checked with some folks internally and here's what I got:

  • We have Windows.Data.Pdf APIs, but those only allow parsing and rendering of an existing PDF file
  • There is no off-the-shelf WinRT API to generate a PDF

So I think your best bet would be to try to get dinkToPdf or something like it working on uwp.

@omdxp
Copy link
Author

omdxp commented May 21, 2021

@asklar Thanks again for looking for this! can't wait to WebView2 to be implemented in react-native-webview. As for DinkToPdf I had a problem to build the app in release, it worked just fine in debug so what I did as the solution and I know it's not optimal is that I added the bin folder for wkhtmltopdf in the user's path and then call the command in background process. It does the job but I know it's not optimal solution..

@emanuelmartin
Copy link

@Omar-Belghaouti, could you please share how your workaround works?

Besides it's or it's not the optimal solution, I would like to solve same issue as u.

Thanks!!

@omdxp
Copy link
Author

omdxp commented Jun 8, 2021

@Omar-Belghaouti, could you please share how your workaround works?

Besides it's or it's not the optimal solution, I would like to solve same issue as u.

Thanks!!

Of course @emanuelmartin , what I did is to add wkhtmltopdf bin folder to the user's Path as an environment variable and then call it from C# by A ReactMethod as the following code shows:

namespace Project 
{
      [ReactModule]
      public sealed class ConvertHtmlToPdfHelper 
      {
           [ReactMethod("convertHtmlToPdf")]
           public async Task<string> ConvertHtmlToPdf(string html)
           {
                 string htmlFilePath = ApplicationData.Current.LocalCacheFolder.Path + "\\file.html";
                 string pdfFilePath = ApplicationData.Current.LocalCacheFolder.Path + "\\file.pdf";
                 await File.WriteAllTextAsync(htmlFilePath, html);
                 Process p = new Process();
                 p.StartInfo.FileName = "cmd.exe";
                 p.StartInfo.Arguments = "/c wkhtmltopdf.exe -g -s A6 -B 0 -L 0 -R 0 -T 0 " + htmlFilePath + " " + pdfFilePath; // Basically here you can add the arguments you need for this command
                 p.StartInfo.WorkingDirectory = ApplicationData.Current.LocalCacheFolder.Path;
                 p.StartInfo.CreateNoWindow = true;
                 p.Start();
                 p.WaitForExit();
                 return pdfFilePath;
           }
      }
}

And then to call it from React Native:

import {NativeModules} from 'react-native';
const convertHtmlToPdf = async () => {
      let html = '<h1>Hello, World!</h1>';
      const pdfFilePath = await NativeModules.ConvertHtmlToPdfHelper.convertHtmlToPdf(html);
      return pdfFilePath;
}

@emanuelmartin
Copy link

Thanks @Omar-Belghaouti! Gonna try it, looks superb 👍

@amineProjects
Copy link

Hi, @Omar-Belghaouti, could you please share how your workaround works in more details I am new to react native windows and c#.
after I tried your solution I keep getting the error: The target "Deploy" does not exist in the project
Screenshot 2021-08-18 234517

Thanks!!

@asklar
Copy link
Member

asklar commented Aug 18, 2021

@amineProjects looks like you might be using an old version of the framework, please make sure you create the app / module RNW with 0.64 (we're about to ship 0.65 next Monday).

@amineProjects
Copy link

I upgraded to RNW 0.64 and the problem was solved but I can't find my method in NtiveModules, I don't know if my native module is linked properly, in the docs https://microsoft.github.io/react-native-windows/docs/native-modules#2-registering-your-native-module shwo how to register a c# native module with c# application but in my case I have a c++ application
so I don't know what to do?
thank you in advance

@omdxp
Copy link
Author

omdxp commented Aug 19, 2021

@amineProjects if you have a c++ project instead of c# make sure to include the library in the pch.h header file (you'll find in details how to link in their website)

@amineProjects
Copy link

amineProjects commented Aug 19, 2021

Screenshot 2021-08-19 203037
hanotywin is the main app created with react native it is in c++ and HtmlToPDF is the react module i try to link, it is in c#
if I want to to include in pch.h header I need to have winrt/HtmlToPDF.h but can I mix c# and c++ file in the same project?
like i said i don't know anything about c++ and my c# knowlage is very week so I beg your understanding if I am messing something

@omdxp
Copy link
Author

omdxp commented Aug 21, 2021

@amineProjects You can mix C# with C++ using winrt, you just need to look for docs on how to do it, and there's no better place than the official microsoft page for it. I suggest you if you don't wanna be bothered with the long process to reinitialize the react native project for windows with C# instead of C++ so it can be easy to implement the modules you need.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Extensions Tracks issues against community modules and extensions Recommend: Not Planned Recommend that issue should be given Not Planned milestone.
Projects
Development

No branches or pull requests

7 participants