Implementing Office Documents Viewer in Mobile Application
.docx, .xlsx, .pptx — Office Open XML formats based on ZIP archives with XML inside. Unlike PDF, they have no standard renderer on mobile platforms. Each manufacturer solves it differently: Microsoft provides SDK, Google — Document Viewer API, others — third-party libraries with variable table and formula rendering quality.
Three Strategies
1. Server-side conversion to PDF/images: document uploads to your server, converts via LibreOffice/unoserver, returns as PDF or PNG set. Client — ready-to-display format. Pros: predictable rendering, no mobile SDK dependency. Cons: conversion delay, document transfer through server (GDPR issues for sensitive data).
2. Native OS viewer: open document in system app (Microsoft Office, QuickLook on iOS). Goes outside your app — sometimes unacceptable.
3. Client-side rendering library: embedded renderer in React Native/Flutter. Limited format support, but no server dependency.
iOS: QuickLook and QLPreviewController
iOS provides QLPreviewController — system viewer supporting .docx, .xlsx, .pptx, .pdf, .txt, images, archives. Embeds in app via native module:
@objc func previewDocument(_ filePath: String) {
DispatchQueue.main.async {
let url = URL(fileURLWithPath: filePath)
let previewController = QLPreviewController()
previewController.dataSource = self
UIApplication.shared.windows.first?.rootViewController?
.present(previewController, animated: true)
}
}
QuickLook renders Microsoft documents via system engine — quality identical to Microsoft Office on iOS. Limitation: view-only, no editing.
In React Native: react-native-doc-viewer uses QLPreviewController under the hood for iOS.
Android: No Unified System Viewer
Android lacks built-in QLPreviewController equivalent for Office documents. Options:
Intent ACTION_VIEW: launches external app (Google Drive Docs, Microsoft Office, WPS Office). User must have at least one. If not — app crashes with ActivityNotFoundException. Mandatory check:
val intent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(fileUri, getMimeType(filePath))
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
}
val resolveInfo = packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY)
if (resolveInfo != null) {
startActivity(intent)
} else {
// Fallback: suggest installing Google Docs or open as PDF
}
Aspose.Words for Android via Java: commercial SDK, renders .docx without installed Office. Quality close to Microsoft Word. License from $999/year.
Android WebView + Google Docs Viewer: https://docs.google.com/viewer?url=<encoded_url>. Works for public files. For private — temporarily host file on accessible URL or use Google Drive API for sharing.
react-native-doc-viewer: Cross-platform Wrapper
import FileViewer from 'react-native-file-viewer';
import RNFS from 'react-native-fs';
const openDocument = async (url: string, filename: string) => {
const localPath = `${RNFS.CachesDirectoryPath}/${filename}`;
const exists = await RNFS.exists(localPath);
if (!exists) {
await RNFS.downloadFile({ fromUrl: url, toFile: localPath }).promise;
}
await FileViewer.open(localPath, {
showOpenWithDialog: true,
showAppsSuggestions: true,
});
};
On iOS FileViewer uses QLPreviewController. On Android — ACTION_VIEW with file:// URI via FileProvider (direct file:// blocked on Android 7+).
Server-side Conversion: LibreOffice Headless
For maximum compatibility and privacy:
libreoffice --headless --convert-to pdf --outdir /output /input/document.docx
unoserver — REST API over LibreOffice for production. Typical .docx conversion takes 1–3 seconds. Cache result by file hash — don't convert same twice.
Comparison of Approaches
| Approach | iOS | Android | Privacy | Delay |
|---|---|---|---|---|
| QLPreviewController | Excellent | — | High | None |
| Intent + third-party | — | Depends | Medium | None |
| Server conversion | Excellent | Excellent | Low | 1–5 sec |
| Aspose SDK | Excellent | Excellent | High | None |
| Google Docs Viewer | Good | Good | Low | 2–4 sec |
Assessment
QuickLook + Android Intent with fallback to server conversion: 2–4 weeks. With caching and offline support: 4–6 weeks.







