Skip to content

feat!: Plugin implementation #1

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

Merged
merged 9 commits into from
Mar 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,71 @@
# Contributing

This guide provides instructions for contributing to this Capacitor plugin.

## Native code

This repository contains minimal code for native Android and iOS. The implementation for native mobile exists in separate repositories:

- [Contributing for Android](https://github.com/ionic-team/ion-android-fileviewer?tab=readme-ov-file#contributing)
- [Contributing for iOS](https://github.com/ionic-team/ion-ios-fileviewer?tab=readme-ov-file#contributing)

## Developing

### Local Setup

1. Fork and clone the repo, uncheking the clone `main` branch only option.
2. If you plan to create a new feature or fix a bug, checkout `development` branch (in general Pull Requests should be open for that branch).
3. Install the dependencies.

```shell
npm install
```

4. Install SwiftLint if you're on macOS.

```shell
brew install swiftlint
```

### Scripts

#### `npm run build`

Build the plugin web assets and generate plugin API documentation using [`@capacitor/docgen`](https://github.com/ionic-team/capacitor-docgen).

It will compile the TypeScript code from `src/` into ESM JavaScript in `dist/esm/`. These files are used in apps with bundlers when your plugin is imported.

Then, Rollup will bundle the code into a single file at `dist/plugin.js`. This file is used in apps without bundlers by including it as a script in `index.html`.

#### `npm run verify`

Build and validate the web and native projects.

This is useful to run in CI to verify that the plugin builds for all platforms.

#### `npm run lint` / `npm run fmt`

Check formatting and code quality, autoformat/autofix if possible.

This template is integrated with ESLint, Prettier, and SwiftLint. Using these tools is completely optional, but the [Capacitor Community](https://github.com/capacitor-community/) strives to have consistent code style and structure for easier cooperation.

## Commits/PR's

Commits and PR's should use the [conventional-commits](https://www.conventionalcommits.org/) format so the release process can version and create changelog correctly.

## Publishing

Publishing is automated based on the branch committed to. When a commit or merge is made to a branch a release that corresponds with the branch will be created:

| Branch Name | Build Type | NPM Tag | Example NPM Version |
| ----------- | ----------------------------- | ------- | ---------------------------------- |
| development | dev | dev | @capacitor/file-viewer@1.0.0-dev.1 |
| next | next (these are betas/alphas) | next | @capacitor/file-viewer@1.0.0-next.1 |
| main | latest | latest | @capacitor/file-viewer@1.0.0 |

- Dev work should be done by creating and merging PR's into the `development` branch until a feature set is complete enough to form a release.
- When a feature set is complete enough to form a release, merge the `development` branch into the `next` branch where it becomes a beta/alpha tagged under `next` for testing teams to use before full release. In case a PR is opened from `development` to `next`, avoid squashing the commits, to keep the history.
- Upon completed testing the `next` branch is merged into `main` for a full release to be made. In case a PR is opened from `next` to `main`, avoid squashing the commits, to keep the history.
- The `main` branch should then be merged into `dev` and `next` to keep them up to date with the latest code base.

> **Note**: The [`files`](https://docs.npmjs.com/cli/v7/configuring-npm/package-json#files) array in `package.json` specifies which files get published. If you rename files/directories or add files elsewhere, you may need to update it.
56 changes: 55 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,56 @@
# capacitor-file-viewer
File Viewer plugin for Capacitor ⚡️

<div align="center">
<a href="https://github.com/ionic-team/capacitor-file-viewer">
<img src=".github/assets/logo.png" alt="Logo" width="auto" height="100">
</a>

<h3 align="center">@capacitor/file-viewer</h3>

<p align="center">
The FileViewer API provides mechanisms for opening files and previewing media. Not available on web.
<br />
<a href="https://github.com/ionic-team/cordova-outsystems-file-viewer">🔌 Cordova Plugin</a>
·
<a href="https://github.com/ionic-team/ion-android-fileviewer">🤖 Android Library</a>
·
<a href="https://github.com/ionic-team/ion-ios-fileviewer">🍏 iOS Library</a>
</p>
<p align="center">
<a href="https://github.com/ionic-team/capacitor-file-viewer/issues/new?labels=bug&template=bug-report.md">🐛 Report Bug</a>
·
<a href="https://github.com/ionic-team/capacitor-file-viewer/issues/new?labels=enhancement&template=feature-request.md"> 💡 Request Feature</a>
</p>
</div>

## Install

```bash
npm install @capacitor/file-viewer
npx cap sync
```

## Example

```typescript
import { FileViewer } from "@capacitor/file-viewer";

// can use a plugin like @capacitor/filesystem to get the full path to the file
const openDocument = async () => {
await FileViewer.openDocumentFromLocalPath({
path: "path/to/file.pdf"
});
};

// ios-specific
const previewMedia = async () => {
await FileViewer.previewMediaContentFromUrl({
path: "https://url_hosting_media/file.mp4"
});
}
```

## API

Check the plugin's api [here](packages/capacitor-plugin/README.md).

2 changes: 2 additions & 0 deletions packages/capacitor-plugin/CapacitorFileViewer.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Pod::Spec.new do |s|
s.source_files = 'ios/Sources/FileViewerPlugin/*.{swift,h,m,c,cc,mm,cpp}'
s.ios.deployment_target = '14.0'
#s.dependency 'FileViewerLib', spec='~> 1.0'
# temporary xcframeowrk dependency - TODO update to official pod (commented line above) once published
s.vendored_frameworks = 'ios/Sources/*/IONFileViewerLib.xcframework'
s.dependency 'Capacitor'
s.swift_version = '5.1'
end
9 changes: 8 additions & 1 deletion packages/capacitor-plugin/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,18 @@ let package = Package(
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", branch: "7.0.0")
],
targets: [
.binaryTarget(
name: "IONFileViewerLib",
// url: "https://github.com/ionic-team/ion-ios-fileviewer/releases/download/1.0.0/IONFileViewerLib.zip",
// checksum: "<compute_checksum>" // sha-256
path: "./ios/Sources/FileViewerPlugin/IONFileViewerLib.xcframework"
),
.target(
name: "FileViewerPlugin",
dependencies: [
.product(name: "Capacitor", package: "capacitor-swift-pm"),
.product(name: "Cordova", package: "capacitor-swift-pm")
.product(name: "Cordova", package: "capacitor-swift-pm"),
"IONFileViewerLib"
],
path: "ios/Sources/FileViewerPlugin"),
.testTarget(
Expand Down
201 changes: 194 additions & 7 deletions packages/capacitor-plugin/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,48 @@
# @capacitor/file-viewer

The FileViewer API provides mechanisms for opening files and previewing media. Not available on web.

The media preview methods are currently only supported on iOS. It uses a built-in player.

## Install

```bash
npm install @capacitor/file-viewer
npx cap sync
```

## Example

```typescript
import { FileViewer } from "@capacitor/file-viewer";

// can use a plugin like @capacitor/filesystem to get the full path to the file
const openDocument = async () => {
await FileViewer.openDocumentFromLocalPath({
path: "path/to/file.pdf"
});
};

// ios-specific
const previewMedia = async () => {
await FileViewer.previewMediaContentFromUrl({
path: "https://url_hosting_media/file.mp4"
});
}
```

## API

<docgen-index>

* [`echo(...)`](#echo)
* [`openDocumentFromLocalPath(...)`](#opendocumentfromlocalpath)
* [`openDocumentFromResources(...)`](#opendocumentfromresources)
* [`openDocumentFromUrl(...)`](#opendocumentfromurl)
* [`previewMediaContentFromLocalPath(...)`](#previewmediacontentfromlocalpath)
* [`previewMediaContentFromResources(...)`](#previewmediacontentfromresources)
* [`previewMediaContentFromUrl(...)`](#previewmediacontentfromurl)
* [Interfaces](#interfaces)
* [Type Aliases](#type-aliases)

</docgen-index>

Expand All @@ -13,22 +51,171 @@ For list of existing error codes, see [Errors](#errors).
<docgen-api>
<!--Update the source file JSDoc comments and rerun docgen to update the docs below-->

### echo(...)
File Viewer API

Only available in Native Android and iOS; not available for Web / PWAs.

### openDocumentFromLocalPath(...)

```typescript
openDocumentFromLocalPath(options: OpenFromLocalPathOptions) => Promise<void>
```

Open a file stored in the local file system

| Param | Type |
| ------------- | ----------------------------------------------------------------------------- |
| **`options`** | <code><a href="#openfromlocalpathoptions">OpenFromLocalPathOptions</a></code> |

**Since:** 1.0.0

--------------------


### openDocumentFromResources(...)

```typescript
openDocumentFromResources(options: OpenFromResourcesOptions) => Promise<void>
```

Open an app resource file

| Param | Type |
| ------------- | ----------------------------------------------------------------------------- |
| **`options`** | <code><a href="#openfromresourcesoptions">OpenFromResourcesOptions</a></code> |

**Since:** 1.0.0

--------------------


### openDocumentFromUrl(...)

```typescript
openDocumentFromUrl(options: OpenFromUrlOptions) => Promise<void>
```

Open a file from a remote url

| Param | Type |
| ------------- | ----------------------------------------------------------------- |
| **`options`** | <code><a href="#openfromurloptions">OpenFromUrlOptions</a></code> |

**Since:** 1.0.0

--------------------


### previewMediaContentFromLocalPath(...)

```typescript
echo(options: { value: string; }) => Promise<{ value: string; }>
previewMediaContentFromLocalPath(options: PreviewMediaFromLocalPathOptions) => Promise<void>
```

| Param | Type |
| ------------- | ------------------------------- |
| **`options`** | <code>{ value: string; }</code> |
Preview a media file (namely, video) stored in the local file system.
Only implemented in iOS. Android defaults to `openDocumentFromLocalPath`.

**Returns:** <code>Promise&lt;{ value: string; }&gt;</code>
| Param | Type |
| ------------- | ----------------------------------------------------------------------------- |
| **`options`** | <code><a href="#openfromlocalpathoptions">OpenFromLocalPathOptions</a></code> |

**Since:** 1.0.0

--------------------


### previewMediaContentFromResources(...)

```typescript
previewMediaContentFromResources(options: PreviewMediaFromResourcesOptions) => Promise<void>
```

Preview a media file (namely, video) from the app's resources.
Only implemented in iOS. Android defaults to `openDocumentFromResources`.

| Param | Type |
| ------------- | ----------------------------------------------------------------------------- |
| **`options`** | <code><a href="#openfromresourcesoptions">OpenFromResourcesOptions</a></code> |

**Since:** 1.0.0

--------------------


### previewMediaContentFromUrl(...)

```typescript
previewMediaContentFromUrl(options: PreviewMediaFromUrlOptions) => Promise<void>
```

Preview a media file (namely, video) from a remote url.
Only implemented in iOS. Android defaults to `openDocumentFromUrl`.

| Param | Type |
| ------------- | ----------------------------------------------------------------- |
| **`options`** | <code><a href="#openfromurloptions">OpenFromUrlOptions</a></code> |

**Since:** 1.0.0

--------------------


### Interfaces


#### OpenFromLocalPathOptions

| Prop | Type | Description | Since |
| ---------- | ------------------- | ------------------------------------------ | ----- |
| **`path`** | <code>string</code> | The full absolute path to the file to open | 1.0.0 |


#### OpenFromResourcesOptions

| Prop | Type | Description | Since |
| ---------- | ------------------- | ---------------------------------------------- | ----- |
| **`path`** | <code>string</code> | The relative path to the resource file to open | 1.0.0 |


#### OpenFromUrlOptions

| Prop | Type | Description | Since |
| --------- | ------------------- | ------------------------------------------- | ----- |
| **`url`** | <code>string</code> | The remote url pointing to the file to open | 1.0.0 |


### Type Aliases


#### PreviewMediaFromLocalPathOptions

<code><a href="#openfromlocalpathoptions">OpenFromLocalPathOptions</a></code>


#### PreviewMediaFromResourcesOptions

<code><a href="#openfromresourcesoptions">OpenFromResourcesOptions</a></code>


#### PreviewMediaFromUrlOptions

<code><a href="#openfromurloptions">OpenFromUrlOptions</a></code>

</docgen-api>

### Errors

The plugin returns the following errors with specific codes on native Android and iOS:

| Error code | Platform(s) | Message |
|-------------------|------------------|------------------------------|
| OS-PLUG-FLVW-0004 | Android, iOS | The file you are trying to open does not exist. |
| OS-PLUG-FLVW-0005 | Android, iOS | The URL you are trying to open is malformed. |
| OS-PLUG-FLVW-0006 | Android, iOS | Path of the file to open is either null or empty. |
| OS-PLUG-FLVW-0007 | Android, iOS | URL to open is either null or empty. |
| OS-PLUG-FLVW-0008 | Android, iOS | Could not open the file. |
| OS-PLUG-FLVW-0009 | Android, iOS | Invalid parameters. |
| OS-PLUG-FLVW-0010 | Android | There is no app to open this file. |
| OS-PLUG-FLVW-0011 | iOS | Cordova / Capacitor bridge isn’t initialized. |
| OS-PLUG-FLVW-0012 | iOS | The download failed. |
| OS-PLUG-FLVW-0013 | iOS | The file has no extension. |
Loading