Xamarin PDF 생성기: IronPDF로 모바일 PDF 앱 구축하기
Xamarin.Forms에서 PDF 파일을 생성하는 것은 까다로울 수 있습니다. .NET PDF 라이브러리 대부분은 모바일 앱을 직접 지원하지 않으며, 장치에서 PDF 문서를 생성하려고 하면 종종 오류 또는 누락된 기능이 발생합니다. 그때 IronPDF가 등장합니다.
IronPDF는 Xamarin.Forms 앱 내에서 네이티브로 실행되지는 않지만 서버 측 API 접근 방식으로 그 격차를 깔끔하게 메울 수 있습니다. 모바일 앱은 API로 HTML 콘텐츠를 전송하고 결과물로 완료된 PDF 파일을 받습니다 -- 이를 통해 양식, 헤더, 푸터, 이미지 및 사용자 정의 레이아웃을 포함한 전문 PDF 생성을 사용할 수 있습니다.
중요 참고 사항: Microsoft는 2024년 5월에 Xamarin의 지원을 종료했습니다. 새로운 프로젝트의 경우 .NET MAUI가 권장되는 후속 제품이며 IronPDF를 더 직접적으로 지원합니다. 이 가이드는 유지보수를 받고 있는 레거시 Xamarin 프로젝트를 위한 서버 측 패턴을 다루고, 새로운 팀들이 시작할 때의 MAUI로의 마이그레이션 경로를 설명합니다.
모바일 PDF 생성을 위한 서버 측 접근 방식이 왜 작동합니까?
IronPDF는 HTML 콘텐츠를 CSS, JavaScript 및 복잡한 레이아웃에 대한 완전한 지원으로 세련된 PDF 문서로 변환하는 데 뛰어납니다. IronPDF를 전용 서버에서 실행함으로써 -- 모바일 애플리케이션 내부에서 실행하는 것이 아니라 -- iOS 및 Android에서 직접 장치에서 PDF 렌더링을 방해하는 플랫폼 제약을 피해갈 수 있습니다.
서버 측 패턴은 여러 가지 구체적인 이점을 제공합니다:
- 일관된 출력: 글꼴, 이미지 및 CSS가 서버 측에서 해결되어 Android와 iOS 하드웨어 간의 렌더링 차이가 사라집니다.
- 기능 접근성: IronPDF 기능은 PDF 양식 생성, 디지털 서명, 워터마크 및 다중 페이지 레이아웃과 같은 모든 기능이 서버에서 제한 없이 사용 가능합니다.
- 가벼운 모바일 앱: 장치는 HTTP 요청을 보내고 반환된 PDF 바이트를 저장하기만 하면 됩니다 -- 휴대폰에는 무거운 PDF 엔진이 실행되지 않습니다.
- 중앙화된 라이선싱: 개별 장치를 각각 라이선싱하는 대신 서버 배포를 다루는 단일 IronPDF 라이선스를 사용합니다.
Xamarin.Forms 클라이언트는 API를 호출하고 바이트 배열을 수신하며 이를 로컬 스토리지에 쓰고 선택적으로 PDF 뷰어를 엽니다. 서버는 나머지 모든 것을 처리합니다.
IronPDF PDF 생성 API는 어떻게 설정합니까?
ASP.NET Core Web API 프로젝트를 생성하여 시작합니다. 이것은 어느 곳에서나 호스팅할 수 있는 표준 .NET 10 최소화 API로, Azure App Service, AWS, 온프레미스 서버 또는 Docker 컨테이너에서 호스팅할 수 있습니다.
IronPDF를 설치하세요
다음 명령어 중 하나를 사용하여 NuGet에서 IronPDF를 설치하십시오:
Install-Package IronPdf
dotnet add package IronPdf
Install-Package IronPdf
dotnet add package IronPdf
PDF 컨트롤러 생성
IronPDF가 설치되면, HTML을 수신하고 PDF를 반환하는 컨트롤러를 추가합니다:
using IronPdf;
using Microsoft.AspNetCore.Mvc;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
namespace PdfGenerationApi.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class PdfController : ControllerBase
{
[HttpPost("generate")]
public async Task<IActionResult> GeneratePdf([FromBody] PdfRequest request)
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 25;
renderer.RenderingOptions.MarginBottom = 25;
renderer.RenderingOptions.MarginLeft = 20;
renderer.RenderingOptions.MarginRight = 20;
var pdf = await renderer.RenderHtmlAsPdfAsync(request.HtmlContent);
return File(pdf.BinaryData, "application/pdf", "document.pdf");
}
}
public class PdfRequest
{
public string HtmlContent { get; set; } = string.Empty;
}
}
using IronPdf;
using Microsoft.AspNetCore.Mvc;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
namespace PdfGenerationApi.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class PdfController : ControllerBase
{
[HttpPost("generate")]
public async Task<IActionResult> GeneratePdf([FromBody] PdfRequest request)
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 25;
renderer.RenderingOptions.MarginBottom = 25;
renderer.RenderingOptions.MarginLeft = 20;
renderer.RenderingOptions.MarginRight = 20;
var pdf = await renderer.RenderHtmlAsPdfAsync(request.HtmlContent);
return File(pdf.BinaryData, "application/pdf", "document.pdf");
}
}
public class PdfRequest
{
public string HtmlContent { get; set; } = string.Empty;
}
}
Imports IronPdf
Imports Microsoft.AspNetCore.Mvc
Dim builder = WebApplication.CreateBuilder(args)
builder.Services.AddControllers()
Dim app = builder.Build()
app.MapControllers()
app.Run()
Namespace PdfGenerationApi.Controllers
<ApiController>
<Route("api/[controller]")>
Public Class PdfController
Inherits ControllerBase
<HttpPost("generate")>
Public Async Function GeneratePdf(<FromBody> request As PdfRequest) As Task(Of IActionResult)
Dim renderer = New ChromePdfRenderer()
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4
renderer.RenderingOptions.MarginTop = 25
renderer.RenderingOptions.MarginBottom = 25
renderer.RenderingOptions.MarginLeft = 20
renderer.RenderingOptions.MarginRight = 20
Dim pdf = Await renderer.RenderHtmlAsPdfAsync(request.HtmlContent)
Return File(pdf.BinaryData, "application/pdf", "document.pdf")
End Function
End Class
Public Class PdfRequest
Public Property HtmlContent As String = String.Empty
End Class
End Namespace
ChromePdfRenderer은 최신 브라우저와 똑같이 HTML을 렌더링하기 위해 Chromium 기반 엔진을 사용합니다. HTML에서 PDF로의 변환은 CSS 애니메이션, 내장 폰트, SVG 그래픽 및 JavaScript 생성 콘텐츠를 존중합니다. 용지 크기 및 여백 설정은 최종 문서 레이아웃으로 직접 변환됩니다.
머리글과 바닥글 추가
전문 문서의 경우 렌더러를 호출하기 전에 헤더와 푸터를 추가하세요:
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
HtmlFragment = "<div style='text-align:right; font-size:12px; color:#555;'>Confidential -- Page {page} of {total-pages}</div>",
DrawDividerLine = true
};
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = "<div style='text-align:center; font-size:11px;'>Generated by MyCompany App</div>"
};
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
HtmlFragment = "<div style='text-align:right; font-size:12px; color:#555;'>Confidential -- Page {page} of {total-pages}</div>",
DrawDividerLine = true
};
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = "<div style='text-align:center; font-size:11px;'>Generated by MyCompany App</div>"
};
Imports System
renderer.RenderingOptions.HtmlHeader = New HtmlHeaderFooter With {
.HtmlFragment = "<div style='text-align:right; font-size:12px; color:#555;'>Confidential -- Page {page} of {total-pages}</div>",
.DrawDividerLine = True
}
renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter With {
.HtmlFragment = "<div style='text-align:center; font-size:11px;'>Generated by MyCompany App</div>"
}
코드-2197--@@ 및 @@--코드-2198--@@와 같은 페이지 번호 토큰은 렌더링 시점에 자동으로 확인됩니다.
Xamarin 클라이언트는 어떻게 구현합니까?
Xamarin.Forms 애플리케이션에서 API를 호출하는 서비스 클래스를 만듭니다. 서비스는 간결하게 유지합니다 -- 그 역할은 HTML 페이로드를 직렬화하고, 이를 전송하며, 호출자에게 원시 PDF 바이트를 반환하는 것뿐입니다.
using System.Net.Http;
using System.Text;
using System.Text.Json;
namespace XamarinPdfApp.Services
{
public class PdfService
{
private readonly HttpClient _httpClient;
private const string ApiUrl = "https://your-api.example.com/api/pdf/generate";
public PdfService()
{
_httpClient = new HttpClient
{
Timeout = TimeSpan.FromSeconds(60)
};
}
public async Task<byte[]> GeneratePdfAsync(string htmlContent)
{
var payload = new { HtmlContent = htmlContent };
var json = JsonSerializer.Serialize(payload);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync(ApiUrl, content);
if (response.IsSuccessStatusCode)
return await response.Content.ReadAsByteArrayAsync();
var error = await response.Content.ReadAsStringAsync();
throw new InvalidOperationException($"PDF generation failed ({(int)response.StatusCode}): {error}");
}
}
}
using System.Net.Http;
using System.Text;
using System.Text.Json;
namespace XamarinPdfApp.Services
{
public class PdfService
{
private readonly HttpClient _httpClient;
private const string ApiUrl = "https://your-api.example.com/api/pdf/generate";
public PdfService()
{
_httpClient = new HttpClient
{
Timeout = TimeSpan.FromSeconds(60)
};
}
public async Task<byte[]> GeneratePdfAsync(string htmlContent)
{
var payload = new { HtmlContent = htmlContent };
var json = JsonSerializer.Serialize(payload);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync(ApiUrl, content);
if (response.IsSuccessStatusCode)
return await response.Content.ReadAsByteArrayAsync();
var error = await response.Content.ReadAsStringAsync();
throw new InvalidOperationException($"PDF generation failed ({(int)response.StatusCode}): {error}");
}
}
}
Imports System.Net.Http
Imports System.Text
Imports System.Text.Json
Namespace XamarinPdfApp.Services
Public Class PdfService
Private ReadOnly _httpClient As HttpClient
Private Const ApiUrl As String = "https://your-api.example.com/api/pdf/generate"
Public Sub New()
_httpClient = New HttpClient With {
.Timeout = TimeSpan.FromSeconds(60)
}
End Sub
Public Async Function GeneratePdfAsync(htmlContent As String) As Task(Of Byte())
Dim payload = New With {Key .HtmlContent = htmlContent}
Dim json = JsonSerializer.Serialize(payload)
Dim content = New StringContent(json, Encoding.UTF8, "application/json")
Dim response = Await _httpClient.PostAsync(ApiUrl, content)
If response.IsSuccessStatusCode Then
Return Await response.Content.ReadAsByteArrayAsync()
End If
Dim error = Await response.Content.ReadAsStringAsync()
Throw New InvalidOperationException($"PDF generation failed ({CInt(response.StatusCode)}): {error}")
End Function
End Class
End Namespace
60초 타임아웃은 많은 이미지나 CSS 리소스가 포함된 복잡한 HTML 문서를 수용합니다. 매우 큰 파일의 경우, 바이너리를 직접 스트리밍하는 대신 API에서 미리 서명된 다운로드 URL을 반환하는 것을 고려하세요 -- 이렇게 하면 모바일 메모리 사용량을 예측할 수 있습니다.
기기에 PDF 파일을 저장하고 여는 방법은?
서비스가 바이트 배열을 반환하면 기기 스토리지에 이를 기록하고 플랫폼 PDF 뷰어에서 엽니다. Xamarin.Forms는 DependencyService 패턴을 사용하여 플랫폼별 구현을 호출합니다.
공유 코드에서 인터페이스를 정의합니다:
using System.Threading.Tasks;
namespace XamarinPdfApp.Interfaces
{
public interface ISaveFile
{
Task<string> SavePdfAsync(string filename, byte[] pdfData);
}
}
using System.Threading.Tasks;
namespace XamarinPdfApp.Interfaces
{
public interface ISaveFile
{
Task<string> SavePdfAsync(string filename, byte[] pdfData);
}
}
Imports System.Threading.Tasks
Namespace XamarinPdfApp.Interfaces
Public Interface ISaveFile
Function SavePdfAsync(filename As String, pdfData As Byte()) As Task(Of String)
End Interface
End Namespace
DependencyService를 사용하여 iOS 구현을 등록하세요:
using Foundation;
using QuickLook;
using UIKit;
using XamarinPdfApp.Interfaces;
using Xamarin.Forms;
[assembly: Dependency(typeof(XamarinPdfApp.iOS.SaveFileIOS))]
namespace XamarinPdfApp.iOS
{
public class SaveFileIOS : ISaveFile
{
public async Task<string> SavePdfAsync(string filename, byte[] pdfData)
{
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var filePath = System.IO.Path.Combine(documents, filename);
await System.IO.File.WriteAllBytesAsync(filePath, pdfData);
return filePath;
}
}
}
using Foundation;
using QuickLook;
using UIKit;
using XamarinPdfApp.Interfaces;
using Xamarin.Forms;
[assembly: Dependency(typeof(XamarinPdfApp.iOS.SaveFileIOS))]
namespace XamarinPdfApp.iOS
{
public class SaveFileIOS : ISaveFile
{
public async Task<string> SavePdfAsync(string filename, byte[] pdfData)
{
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var filePath = System.IO.Path.Combine(documents, filename);
await System.IO.File.WriteAllBytesAsync(filePath, pdfData);
return filePath;
}
}
}
Imports Foundation
Imports QuickLook
Imports UIKit
Imports XamarinPdfApp.Interfaces
Imports Xamarin.Forms
<Assembly: Dependency(GetType(XamarinPdfApp.iOS.SaveFileIOS))>
Namespace XamarinPdfApp.iOS
Public Class SaveFileIOS
Implements ISaveFile
Public Async Function SavePdfAsync(filename As String, pdfData As Byte()) As Task(Of String) Implements ISaveFile.SavePdfAsync
Dim documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
Dim filePath = System.IO.Path.Combine(documents, filename)
Await System.IO.File.WriteAllBytesAsync(filePath, pdfData)
Return filePath
End Function
End Class
End Namespace
Android의 경우 앱의 외부 파일 디렉터리에 작성하고 매니페스트에 FileProvider를 등록하여 PDF 뷰어 인텐트에 URI를 전달할 수 있도록 합니다. 공유 코드에서 DependencyService.Get<ISaveFile>() 호출은 런타임에 현재 플랫폼에 등록된 구현을 검색합니다.
모두 연결하기
Xamarin.Forms 페이지나 ViewModel에서 서비스와 플랫폼 저장소를 결합합니다:
var htmlContent = BuildInvoiceHtml(invoice);
var pdfBytes = await _pdfService.GeneratePdfAsync(htmlContent);
var saver = DependencyService.Get<ISaveFile>();
var filePath = await saver.SavePdfAsync("invoice.pdf", pdfBytes);
await Launcher.OpenAsync(new OpenFileRequest
{
File = new ReadOnlyFile(filePath, "application/pdf")
});
var htmlContent = BuildInvoiceHtml(invoice);
var pdfBytes = await _pdfService.GeneratePdfAsync(htmlContent);
var saver = DependencyService.Get<ISaveFile>();
var filePath = await saver.SavePdfAsync("invoice.pdf", pdfBytes);
await Launcher.OpenAsync(new OpenFileRequest
{
File = new ReadOnlyFile(filePath, "application/pdf")
});
Dim htmlContent = BuildInvoiceHtml(invoice)
Dim pdfBytes = Await _pdfService.GeneratePdfAsync(htmlContent)
Dim saver = DependencyService.Get(Of ISaveFile)()
Dim filePath = Await saver.SavePdfAsync("invoice.pdf", pdfBytes)
Await Launcher.OpenAsync(New OpenFileRequest With {
.File = New ReadOnlyFile(filePath, "application/pdf")
})
이는 사용자가 설치한 뷰어에서 저장된 PDF를 열며, 이는 일반적으로 iOS 및 Android의 네이티브 PDF 애플리케이션입니다.
전문적 송장 및 보고서 PDF를 생성하려면 어떻게 해야 합니까?
PDF의 품질은 거의 전적으로 렌더러에 전달되는 HTML 템플릿의 품질에 달려 있습니다. C# 문자열 보간이나 Scriban과 같은 템플릿 라이브러리를 사용하여 데이터 기반 HTML을 구축하세요:
public string BuildInvoiceHtml(Invoice invoice)
{
var rows = string.Join(
"\n",
invoice.목s.Select(i =>
$"<tr><td>{i.Name}</td><td>{i.Quantity}</td><td>${i.UnitPrice:F2}</td><td>${i.Total:F2}</td></tr>"
)
);
return $@"<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<style>
body {{ font-family: Arial, sans-serif; color: #333; margin: 0; padding: 30px; }}
h1 {{ color: #1a73e8; }}
table {{ width: 100%; border-collapse: collapse; margin-top: 20px; }}
th {{ background: #1a73e8; color: #fff; padding: 10px; text-align: left; }}
td {{ padding: 10px; border-bottom: 1px solid #e0e0e0; }}
.total {{ font-weight: bold; font-size: 1.1em; text-align: right; margin-top: 15px; }}
</style>
</head>
<body>
<h1>Invoice #{invoice.Number}</h1>
<p>Date: {invoice.Date:yyyy-MM-dd} | Due: {invoice.DueDate:yyyy-MM-dd}</p>
<p>Bill to: <strong>{invoice.ClientName}</strong></p>
<table>
<thead><tr><th>목</th><th>Qty</th><th>Unit Price</th><th>Total</th></tr></thead>
<tbody>{rows}</tbody>
</table>
<p class='total'>Grand Total: ${invoice.GrandTotal:F2}</p>
</body>
</html>";
}
public string BuildInvoiceHtml(Invoice invoice)
{
var rows = string.Join(
"\n",
invoice.목s.Select(i =>
$"<tr><td>{i.Name}</td><td>{i.Quantity}</td><td>${i.UnitPrice:F2}</td><td>${i.Total:F2}</td></tr>"
)
);
return $@"<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<style>
body {{ font-family: Arial, sans-serif; color: #333; margin: 0; padding: 30px; }}
h1 {{ color: #1a73e8; }}
table {{ width: 100%; border-collapse: collapse; margin-top: 20px; }}
th {{ background: #1a73e8; color: #fff; padding: 10px; text-align: left; }}
td {{ padding: 10px; border-bottom: 1px solid #e0e0e0; }}
.total {{ font-weight: bold; font-size: 1.1em; text-align: right; margin-top: 15px; }}
</style>
</head>
<body>
<h1>Invoice #{invoice.Number}</h1>
<p>Date: {invoice.Date:yyyy-MM-dd} | Due: {invoice.DueDate:yyyy-MM-dd}</p>
<p>Bill to: <strong>{invoice.ClientName}</strong></p>
<table>
<thead><tr><th>목</th><th>Qty</th><th>Unit Price</th><th>Total</th></tr></thead>
<tbody>{rows}</tbody>
</table>
<p class='total'>Grand Total: ${invoice.GrandTotal:F2}</p>
</body>
</html>";
}
Imports System
Imports System.Linq
Public Function BuildInvoiceHtml(invoice As Invoice) As String
Dim rows = String.Join(
vbLf,
invoice.목s.Select(Function(i)
$"<tr><td>{i.Name}</td><td>{i.Quantity}</td><td>${i.UnitPrice:F2}</td><td>${i.Total:F2}</td></tr>"
)
)
Return $"
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<style>
body {{ font-family: Arial, sans-serif; color: #333; margin: 0; padding: 30px; }}
h1 {{ color: #1a73e8; }}
table {{ width: 100%; border-collapse: collapse; margin-top: 20px; }}
th {{ background: #1a73e8; color: #fff; padding: 10px; text-align: left; }}
td {{ padding: 10px; border-bottom: 1px solid #e0e0e0; }}
.total {{ font-weight: bold; font-size: 1.1em; text-align: right; margin-top: 15px; }}
</style>
</head>
<body>
<h1>Invoice #{invoice.Number}</h1>
<p>Date: {invoice.Date:yyyy-MM-dd} | Due: {invoice.DueDate:yyyy-MM-dd}</p>
<p>Bill to: <strong>{invoice.ClientName}</strong></p>
<table>
<thead><tr><th>목</th><th>Qty</th><th>Unit Price</th><th>Total</th></tr></thead>
<tbody>{rows}</tbody>
</table>
<p class='total'>Grand Total: ${invoice.GrandTotal:F2}</p>
</body>
</html>"
End Function
ChromePdfRenderer은 이 템플릿을 브라우저에서 볼 때와 똑같이 렌더링합니다. IronPDF의 워터마크 API를 사용하여 워터마크를 추가하거나 기밀 초안을 위한 맞춤 워터마크 디자인을 적용할 수 있습니다. 서명 필드가 필요한 문서의 경우, IronPDF의 서명 지원을 통해 서버 측에서 디지털 서명 플레이스홀더를 내장할 수 있습니다.
Xamarin 앱에서 PDF 양식을 어떻게 처리합니까?
PDF 양식은 모바일 비즈니스 앱에서 일반적으로 요구됩니다 -- 계약서, 온보딩 설문지, 점검 체크리스트 모두 사전 채운 편집 가능한 필드에서 이점을 얻습니다. 서버 API는 필드 데이터와 함께 HTML 템플릿을 받아 양식 값을 내장한 후 PDF를 반환할 수 있습니다:
[HttpPost("form")]
public async Task<IActionResult> GenerateForm([FromBody] FormRequest request)
{
var renderer = new ChromePdfRenderer();
// Render an HTML form template to create an interactive PDF form
var pdf = await renderer.RenderHtmlAsPdfAsync(request.HtmlTemplate);
// Fill known values before returning
var form = pdf.Form;
foreach (var field in request.FieldValues)
{
var pdfField = form.Fields.FirstOrDefault(f => f.Name == field.Key);
if (pdfField is IronPdf.Forms.PdfFormTextFieldField textField)
textField.Value = field.Value;
}
return File(pdf.BinaryData, "application/pdf", "form.pdf");
}
[HttpPost("form")]
public async Task<IActionResult> GenerateForm([FromBody] FormRequest request)
{
var renderer = new ChromePdfRenderer();
// Render an HTML form template to create an interactive PDF form
var pdf = await renderer.RenderHtmlAsPdfAsync(request.HtmlTemplate);
// Fill known values before returning
var form = pdf.Form;
foreach (var field in request.FieldValues)
{
var pdfField = form.Fields.FirstOrDefault(f => f.Name == field.Key);
if (pdfField is IronPdf.Forms.PdfFormTextFieldField textField)
textField.Value = field.Value;
}
return File(pdf.BinaryData, "application/pdf", "form.pdf");
}
Imports Microsoft.AspNetCore.Mvc
Imports IronPdf
<HttpPost("form")>
Public Async Function GenerateForm(<FromBody> request As FormRequest) As Task(Of IActionResult)
Dim renderer As New ChromePdfRenderer()
' Render an HTML form template to create an interactive PDF form
Dim pdf = Await renderer.RenderHtmlAsPdfAsync(request.HtmlTemplate)
' Fill known values before returning
Dim form = pdf.Form
For Each field In request.FieldValues
Dim pdfField = form.Fields.FirstOrDefault(Function(f) f.Name = field.Key)
If TypeOf pdfField Is IronPdf.Forms.PdfFormTextFieldField Then
Dim textField = DirectCast(pdfField, IronPdf.Forms.PdfFormTextFieldField)
textField.Value = field.Value
End If
Next
Return File(pdf.BinaryData, "application/pdf", "form.pdf")
End Function
모바일 클라이언트는 필드 이름과 값을 사전 형태로 보냅니다. 서버는 이를 채우고 사용자가 검토할 수 있는 양식을 반환하여, 남은 필드를 PDF 뷰어에서 완료하고 제출할 수 있습니다.
Xamarin 앱에서 텍스트를 추출하고 PDF를 병합하는 방법은 무엇입니까?
생성을 넘어 IronPDF는 다양한 문서 작업을 지원하여 이를 API 엔드포인트로 노출할 수 있습니다:
- PDF에서 텍스트 추출: PDF 콘텐츠를 파싱하여 문서를 인덱싱하거나 데이터 입력 양식을 미리 채웁니다.
- PDF 병합 또는 분할: 여러 보고서를 하나의 PDF로 결합하거나 대형 문서를 섹션별 파일로 분할합니다.
- PDF를 이미지로 변환: 모바일 UI에 미리 보기 썸네일로 PDF 페이지를 PNG 또는 JPEG로 렌더링합니다.
이 모든 것은 별도의 API 엔드포인트가 됩니다. Xamarin 클라이언트는 이를 다른 REST 리소스처럼 호출하여 모바일 코드가 PDF 로직에서 자유롭고 서버가 권위 있는 문서 프로세서로 작용할 수 있습니다.
일반적인 문제는 무엇입니까, 그리고 어떻게 해결합니까?
서버-클라이언트 아키텍처는 간단하지만 몇몇 생산 문제에 주의를 기울여야 합니다:
| 문제 | 원인 | 권장 수정 |
|---|---|---|
| 요청 시간 초과 | 많은 원격 자산을 포함한 복잡한 HTML은 렌더링하는 데 시간이 걸립니다 | HttpClient.Timeout를 늘리고 렌더링 옵션에서 서버 측 렌더 타임아웃을 설정합니다 |
| 큰 PDF 메모리 급증 | 20 MB PDF를 응답 본문을 통해 스트리밍 | 블롭 스토리지에 업로드하고 짧은 수명의 다운로드 URL을 대신 반환합니다 |
| 오프라인 생성 | 사용자가 PDF 요청 시 장치에 연결이 없음 | 로컬에 요청을 대기열에 추가하고 연결이 복원될 때 다시 시도합니다 |
| 권한 없는 API 액세스 | 엔드포인트가 인터넷에 열려 있음 | JWT나 API 키로 보안을 강화하고 모든 경로에 HTTPS를 강제합니다 |
| 폰트가 내장되지 않음 | 서버 OS에 폰트가 설치되지 않음 | 폰트를 HTML에 base64 데이터 URI 또는 CSS @font-face 규칙으로 내장합니다 |
| iOS 저장소 권한 | 앱이 더 제한적인 샌드박싱을 사용하는 iOS 14+ 대상으로 | 앱 샌드박스 내부의 Environment.SpecialFolder.MyDocuments에 기록 |
제한 속도를 위해 AspNetCoreRateLimit과 같은 라이브러리를 사용하여 ASP.NET Core 측에 미들웨어를 추가합니다. 각 생성 요청을 타이밍 데이터와 함께 기록하여 사용자가 느려지기 전에 느린 템플릿을 감지할 수 있습니다.
Xamarin에서 .NET MAUI로 마이그레이션해야 하나요?
2026년에 새 모바일 프로젝트를 시작하는 경우 .NET MAUI가 적합한 선택입니다. Microsoft는 2024년 5월에 Xamarin 지원이 종료되어 추가 보안 패치나 버그 수정이 없습니다. .NET MAUI는 직접 후계자이며 현재 IronPDF 런타임과 일치하는 .NET 10에서 실행됩니다.
이 가이드에서 설명한 서버 측 아키텍처는 .NET MAUI 앱에도 동일하게 작동합니다 -- 클라이언트 HTTP 코드는 본질적으로 동일합니다; cODE-2204--@@만 MAUI의 기본 제공 종속성 주입으로 대체됩니다. 기존 Xamarin 앱을 유지하는 팀은 MAUI로 마이그레이션을 계획해야 합니다; Microsoft의 공식 .NET MAUI 마이그레이션 가이드는 단계를 자세히 문서화합니다.
IronPDF를 프로덕션으로 배포하고 라이센스를 어떻게 설정합니까?
배포는 간단합니다: Docker를 사용하여 ASP.NET Core API를 컨테이너화하고 Azure App Service, AWS ECS 또는 모든 쿠버네티스 클러스터에 푸시합니다. IronPDF 라이센스 키는 서버에서 환경 변수로 설정되어 있습니다:
IronPdf.License.LicenseKey = Environment.GetEnvironmentVariable("IRONPDF_LICENSE_KEY")
?? throw new InvalidOperationException("IronPDF license key not set.");
IronPdf.License.LicenseKey = Environment.GetEnvironmentVariable("IRONPDF_LICENSE_KEY")
?? throw new InvalidOperationException("IronPDF license key not set.");
Imports System
Imports IronPdf
IronPdf.License.LicenseKey = If(Environment.GetEnvironmentVariable("IRONPDF_LICENSE_KEY"), Throw New InvalidOperationException("IronPDF license key not set."))
적절한 배포 계층을 선택하려면 IronPDF 라이센싱 페이지를 검토하세요. 전체 기능 세트를 테스트하기 위해 무료 체험판 라이센스를 사용할 수 있습니다. 컨테이너화된 또는 서버리스 배포의 경우 라이센스 계층이 동시에 실행되는 서버 인스턴스 수를 다루는지 확인하세요.
라이선싱 후, 스레드 안전 렌더링 설정, PDF/A 준수, 접근성 태그 포함 고급 구성 옵션을 위해 IronPDF 문서를 탐색하세요.
프로덕션 배포 체크리스트
| 목 | 추천 |
|---|---|
| 라이선스 키 | 환경 변수나 비밀 관리자에 저장하고, 소스 코드에는 절대 저장하지 마세요 |
| HTTPS | 모든 API 엔드포인트에 TLS를 강제 적용하세요; 절대 평문 HTTP로 HTML 페이로드를 보내지 마세요 |
| 입증 | JWT 베어러 토큰이나 API 키를 사용하세요; 침해 시 폐기하세요 |
| 캐싱 | 동일한 HTML 페이로드를 짧은 TTL로 캐시하여 중복 렌더를 줄이세요 |
| 배율 조정 | IronPDF는 스레드 안전성 있습니다; 로드 밸런서 뒤에서 여러 API 복제를 실행하세요 |
| 모니터링 | 렌더 지연 시간과 오류율을 추적하세요; 기준치를 초과하는 급증에 대해 알림을 설정하세요 |
서버 측 패턴은 Xamarin 또는 MAUI 클라이언트에 대한 변경 없이 수평적으로 확장됩니다. PDF 생성 볼륨이 증가함에 따라 복제본을 추가하고 로드 밸런서에 의지하여 요청을 고르게 분배하세요.
자주 묻는 질문
IronPDF를 Xamarin.Forms에서 네이티브로 사용할 수 있습니까?
IronPDF는 Xamarin.Forms에서 네이티브로 실행되지 않지만, 서버 측 접근 방식을 사용하여 PDF 생성 및 조작을 처리할 수 있습니다.
모바일 앱에서 PDF 생성을 위해 IronPDF를 사용하는 이점은 무엇입니까?
IronPDF를 사용하면 PDF 파일을 생성하고, 양식을 채우고, 여러 페이지를 처리하며, 이미지, 폰트 및 사용자 정의 레이아웃을 포함할 수 있어, 모바일 앱의 PDF 생성 기능을 향상시킵니다.
Xamarin에서 IronPDF는 어떻게 PDF 생성을 처리하나요?
IronPDF는 Xamarin에서 PDF를 생성하기 위해 서버 측 접근 방식을 사용하며, 일반적으로 모바일 장치에서 지원되지 않는 복잡한 PDF 기능을 활성화합니다.
Xamarin에서 IronPDF를 사용하여 PDF 양식을 채우는 것이 가능합니까?
네, IronPDF는 Xamarin 애플리케이션을 위한 포괄적인 PDF 처리 기능의 일부로 PDF 양식을 채우는 것을 지원합니다.
IronPDF는 Xamarin PDF 생성에서 어떤 문제를 해결합니까?
IronPDF는 서버 측 솔루션을 사용하여 모바일 장치에서 직접 PDF 생성 시 발생하는 오류와 누락된 기능 등 문제를 해결합니다.
IronPDF는 Xamarin 앱에서 PDF에 사용자 정의 레이아웃을 처리할 수 있습니까?
예, IronPDF는 생성된 PDF에 사용자 정의 레이아웃을 포함시킬 수 있어 문서의 디자인과 프레젠테이션을 제어할 수 있습니다.
Xamarin에서 IronPDF를 사용하여 구현할 수 있는 PDF 기능은 무엇입니까?
IronPDF는 Xamarin에서 여러 페이지 문서, 양식 채우기, 이미지 및 글꼴 추가, 사용자 정의 레이아웃 등의 기능 구현을 허용합니다.
IronPDF와 함께 서버 측 접근 방식이 추천되는 이유는 무엇입니까?
서버 측 접근 방식은 모바일 장치의 제약을 우회하여 안정적인 PDF 생성과 고급 기능을 보장하기 때문에 추천됩니다.


