如何在.NET MAUI项目中与Android项目的Java代码进行互操作?

huangapple go评论108阅读模式
英文:

How can I interop with Android project java in .NET MAUI Project?

问题

我尝试在.NET MAUI Blazor混合项目中打印文档。在这个过程中,我注意到了在platform/android文件夹根目录下与Android操作系统进行交互的地方。以下是我在开发该打印代码时所遵循的文档:

  1. 在Android打印管理器中打印照片
  2. 在Android中打印自定义文档

在Android上打印照片是成功的,但现在我想打印自定义文档,因为我想打印PDF。以下是成功打印图像和不成功打印PDF的代码。PDF和图像都可以转换为Base64字符串。

以下是.NET中的接口代码:

namespace PrintMAUI.Services
{
    public interface IPrintCalller
    {
        Task<bool> printImage(byte[] bitmapBytes);
        Task<bool> printPDF(byte[] pdfBytes);
    }
}

在Android平台上创建的类代码:

namespace PrintMAUI.Platforms
{
    public class PrintCaller : MauiAppCompatActivity, IPrintCalller
    {
        public async Task<bool> printImage(byte[] bitmapBytes)
        {
            try
            {
                //Microsoft.Maui.ApplicationModel.Platform.CurrentActivity.Context
               
                PrintHelper photoPrinter = new PrintHelper(Platform.CurrentActivity);
                photoPrinter.ScaleMode = PrintHelper.ScaleModeFill;

                Bitmap bitmap = await BitmapFactory.DecodeByteArrayAsync(bitmapBytes, 0, bitmapBytes.Length);

                photoPrinter.PrintBitmap("Testing Print for BL", bitmap);
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        public async Task<bool> printPDF(byte[] pdfBytes)
        {
            try
            {
                
                PrintManager printManager = Platform.CurrentActivity.GetSystemService(Android.Content.Context.PrintService).JavaCast<PrintManager>();
                string jobName = "simple Print Job";
                printManager.Print(jobName, new CustomPrintDocumentAdapter(pdfBytes), null);
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }
    }
}

自定义打印适配器代码:

using Android.Graphics.Pdf;
using Android.OS;
using Android.Print;
using Android.Print.Pdf;
using Android.Runtime;
using Java.IO;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Android.Print.PrintAttributes;

namespace PrintMAUI.Platforms
{
    public class CustomPrintDocumentAdapter : PrintDocumentAdapter
    {
        //private byte[] data;
        private int totalPages = 0;
        PrintedPdfDocument pdfDocument;
        public CustomPrintDocumentAdapter(byte[] data)
        {
            //this.data = data;
        }
        public override void OnLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras)
        {
            pdfDocument = new PrintedPdfDocument(Platform.CurrentActivity, newAttributes);

            if (cancellationSignal.IsCanceled)
            {
                callback.OnLayoutCancelled();
                return;
            }

            int pages = computePageCount(newAttributes);

            if (pages > 0)
            {
                PrintDocumentInfo pdi = new PrintDocumentInfo.Builder("PDF.pdf")
                    .SetContentType(Android.Print.PrintContentType.Document)
                    .SetPageCount(pages)
                    .Build();
                callback.OnLayoutFinished(pdi, true);
            }
            else
            {
                callback.OnLayoutFailed("Calculations Failed!");
            }
        }
        private bool containsPage(PageRange[] pages, int num)
        {
            //TODO: you have to do it
            return true;
        }
        public override void OnWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback)
        {
            for (int i = 0; i < totalPages; i++)
            {
                // Check to see if this page is in the output range.
                if (containsPage(pages, i))
                {
                    // If so, add it to writtenPagesArray. writtenPagesArray.size()
                    // is used to compute the next output page index.
                    //writtenPagesArray.append(writtenPagesArray.size(), i);
                    PdfDocument.Page page = pdfDocument.StartPage(i);

                    // check for cancellation
                    if (cancellationSignal.IsCanceled)
                    {
                        callback.OnWriteCancelled();
                        pdfDocument.Close();
                        pdfDocument = null;
                        return;
                    }

                    // Rendering is complete, so page can be finalized.
                    pdfDocument.FinishPage(page);
                }
            }

            // Write PDF document to file
            try
            {
                //FileOutputStream stream = new FileOutputStream(destination.FileDescriptor);
                FileStream stream = new FileStream((string)destination.FileDescriptor, FileMode.Create, FileAccess.Write);
                pdfDocument.WriteTo(stream);
            }
            catch (Exception e)
            {
                callback.OnWriteFailed(e.ToString());
                return;
            }
            finally
            {
                pdfDocument.Close();
                pdfDocument = null;
            }
            //PageRange[] writtenPages = computeWrittenPages();
           /// Signal the print framework the document is complete
            callback.OnWriteFinished(pages);

        }

        private int computePageCount(PrintAttributes printAttributes)
        {
            int itemsPerPage = 4;

            MediaSize pageSize = printAttributes.GetMediaSize();
            if (!pageSize.IsPortrait)
            {
                itemsPerPage = 6;
            }

            int printItemCount = 1;

            return (int)Math.Ceiling((double)printItemCount/itemsPerPage);
        }
    }
}

我的做法

  1. 首先,我尝试创建一个单独的项目,其中包含打印机SDK,并从MAUI应用程序调用它。但由于策略限制,这并不起作用。

  2. 然后我尝试将打印机SDK添加到MAUI项目中。但这也不起作用。

  3. 然后我尝试这种方法。我尝试使用Android打印管理器来打印文档。我成功地打印了图像,但我想从字节数组中打印PDF。

我的期望

在CustomPrintDocumentAdapter类中,以下代码行存在问题,无法修复。无论如何,我都会得到转换问题:

FileStream stream = new FileStream((string)destination.FileDescriptor, FileMode.Create, FileAccess.Write);
pdfDocument.WriteTo(stream);

我想知道如何修复它?

其次,我认为这段代码可能有一些需要理解的地方,即CustomPrintDocumentAdapter如何支持打印自定义文档。有人能解释一下吗?

Google文档中有这段代码:

writtenPagesArray.append(writtenPages

<details>
<summary>英文:</summary>

I tried to print documents over .NET MAUI Blazor hybrid Project. When I was doing it, I saw the place interop with android os in platform/android folder root. Here is the documentation I followed when developing that code to print,

1. [Printing Photos in android Print manager](https://developer.android.com/training/printing/photos)
2. [Printing Custom Document in android](https://developer.android.com/training/printing/custom-docs)

Printing photos in android is a success, but now I want to print custom documents because I want to print PDF. Here is a code for successful image print and unsuccessful PDF Print. Both PDF and image can convert to base64 string.

here is code of interface in .NET

namespace PrintMAUI.Services
{
public interface IPrintCalller
{
Task<bool> printImage(byte[] bitmapBytes);
Task<bool> printPDF(byte[] pdfBytes);
}
}


Class Created for android platform

namespace PrintMAUI.Platforms
{
public class PrintCaller : MauiAppCompatActivity, IPrintCalller
{
public async Task<bool> printImage(byte[] bitmapBytes)
{
try
{
//Microsoft.Maui.ApplicationModel.Platform.CurrentActivity.Context

            PrintHelper photoPrinter = new PrintHelper(Platform.CurrentActivity);
photoPrinter.ScaleMode = PrintHelper.ScaleModeFill;
Bitmap bitmap = await BitmapFactory.DecodeByteArrayAsync(bitmapBytes, 0, bitmapBytes.Length);
photoPrinter.PrintBitmap(&quot;Testing Print for BL&quot;, bitmap);
return true;
}catch (Exception ex)
{
return false;
}
}
public async Task&lt;bool&gt; printPDF(byte[] pdfBytes)
{
try
{
PrintManager printManager = Platform.CurrentActivity.GetSystemService(Android.Content.Context.PrintService).JavaCast&lt;PrintManager&gt;();
string jobName = &quot;simple Print Job&quot;;
printManager.Print(jobName, new CustomPrintDocumentAdapter(pdfBytes), null);
return true;
}catch(Exception ex)
{
return false;
}
}
}

}


Custom Print Adapter

using Android.Graphics.Pdf;
using Android.OS;
using Android.Print;
using Android.Print.Pdf;
using Android.Runtime;
using Java.IO;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Android.Print.PrintAttributes;

namespace PrintMAUI.Platforms
{
public class CustomPrintDocumentAdapter : PrintDocumentAdapter
{
//private byte[] data;
private int totalPages = 0;
PrintedPdfDocument pdfDocument;
public CustomPrintDocumentAdapter(byte[] data)
{
//this.data = data;
}
public override void OnLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras)
{
pdfDocument = new PrintedPdfDocument(Platform.CurrentActivity,newAttributes);

        if (cancellationSignal.IsCanceled)
{
callback.OnLayoutCancelled();
return;
}
int pages = computePageCount(newAttributes);
if(pages &gt; 0)
{
PrintDocumentInfo pdi = new PrintDocumentInfo.Builder(&quot;PDF.pdf&quot;)
.SetContentType(Android.Print.PrintContentType.Document)
.SetPageCount(pages)
.Build();
callback.OnLayoutFinished(pdi, true);
}
else
{
callback.OnLayoutFailed(&quot;Calculations Failed!&quot;);
}
}
private bool containsPage(PageRange[] pages,int num)
{
//TODO: you have to do it
return true;
}
public override void OnWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback)
{
for (int i = 0; i &lt; totalPages; i++)
{
// Check to see if this page is in the output range.
if (containsPage(pages, i))
{
// If so, add it to writtenPagesArray. writtenPagesArray.size()
// is used to compute the next output page index.
//writtenPagesArray.append(writtenPagesArray.size(), i);
PdfDocument.Page page = pdfDocument.StartPage(i);
// check for cancellation
if (cancellationSignal.IsCanceled)
{
callback.OnWriteCancelled();
pdfDocument.Close();
pdfDocument = null;
return;
}
// Rendering is complete, so page can be finalized.
pdfDocument.FinishPage(page);
}
}
// Write PDF document to file
try
{
//FileOutputStream stream = new FileOutputStream(destination.FileDescriptor);
FileStream stream = new FileStream((string)destination.FileDescriptor, FileMode.Create, FileAccess.Write);
pdfDocument.WriteTo(stream);
}
catch (Exception e)
{
callback.OnWriteFailed(e.ToString());
return;
}
finally
{
pdfDocument.Close();
pdfDocument = null;
}
//PageRange[] writtenPages = computeWrittenPages();
/// Signal the print framework the document is complete
callback.OnWriteFinished(pages);
}
private int computePageCount(PrintAttributes printAttributes)
{
int itemsPerPage = 4;
MediaSize pageSize = printAttributes.GetMediaSize();
if (!pageSize.IsPortrait)
{
itemsPerPage = 6;
}
int printItemCount = 1;
return (int)Math.Ceiling((double)printItemCount/itemsPerPage);
}
}

}


### What I does
1. First I try to create seperate project with printer SDK and call to it from MAUI app. but it didn&#39;s work because policy restrictions.
2. Then I try to add printer SDK to MAUI Project. It doesn&#39;t work
3. Then I try to this way.I try to use android print manager to print documents. I successful when printing image. but I want to print PDF from it&#39;s byte array. 
### What I Expecting
these lines in customprintdocumentadapter class got issue that cannot be fixed. everyway I got casting issue 

FileStream stream = new FileStream((string)destination.FileDescriptor, FileMode.Create, FileAccess.Write);
pdfDocument.WriteTo(stream);

I want way to fix it?
Second thing is I thaught this code may have some ponts that have to be understand how customprintdocumentadapter support to print custom document. can someone explain?
google documentation have this code

writtenPagesArray.append(writtenPagesArray.size(), i);


but I cant find where is coming from.
</details>
# 答案1
**得分**: 0
实际上不想创建PrintedPdfDocument对象。我可以像这样将我的字节数组传递给文件流:
```csharp
public class CustomPrintDocumentAdapter : PrintDocumentAdapter
{
private byte[] data;
public CustomPrintDocumentAdapter(byte[] data)
{
this.data = data;
}
public override void OnLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras)
{
if (cancellationSignal.IsCanceled)
{
callback.OnLayoutCancelled();
return;
}
int pages = 1;
if (pages &gt; 0)
{
PrintDocumentInfo pdi = new PrintDocumentInfo.Builder(&quot;PDF.pdf&quot;)
.SetContentType(Android.Print.PrintContentType.Document)
.SetPageCount(pages)
.Build();
callback.OnLayoutFinished(pdi, true);
}
else
{
callback.OnLayoutFailed(&quot;Calculations Failed!&quot;);
}
}
public override void OnWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback)
{
try
{
FileOutputStream stream = new FileOutputStream(destination.FileDescriptor);
stream.Write(data);
}
catch (Exception e)
{
callback.OnWriteFailed(e.ToString());
return;
}
callback.OnWriteFinished(pages);
}
}

然后问题得以解决。

英文:

Actually Not wanted to create PrintedPdfDocument Object. I could able to pass my byte array to filestream like this

public class CustomPrintDocumentAdapter : PrintDocumentAdapter
{
private byte[] data;
public CustomPrintDocumentAdapter(byte[] data)
{
this.data = data;
}
public override void OnLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras)
{
if (cancellationSignal.IsCanceled)
{
callback.OnLayoutCancelled();
return;
}
int pages = 1;
if (pages &gt; 0)
{
PrintDocumentInfo pdi = new PrintDocumentInfo.Builder(&quot;PDF.pdf&quot;)
.SetContentType(Android.Print.PrintContentType.Document)
.SetPageCount(pages)
.Build();
callback.OnLayoutFinished(pdi, true);
}
else
{
callback.OnLayoutFailed(&quot;Calculations Failed!&quot;);
}
}
public override void OnWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback)
{
try
{
FileOutputStream stream = new FileOutputStream(destination.FileDescriptor);
stream.Write(data);
}
catch (Exception e)
{
callback.OnWriteFailed(e.ToString());
return;
}
callback.OnWriteFinished(pages);
}
}

Then Problem get solved

huangapple
  • 本文由 发表于 2023年6月22日 17:01:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/76530206.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定