メインコンテンツまでスキップ

In-App SDK を使う

このページでは、In-App SDK を使って簡単なミニアプリを作成する方法を紹介します。 また、Service APIによる通知の送信も行います。

必要環境の用意

このページでは、Node.js 20 と npm 10 を使用して説明します。 他のバージョンを利用する場合は、オプションなどが異なる場合がありますので、適宜読み替えてください。

サービスの作成

まずは、作成するミニアプリのサービスを作成してください。サービスの作成を参照してください。

プロジェクトの作成

npm create vite@latest コマンドでプロジェクトを作成します。

  • Project name には 好きな名前を入力してください。
  • Select a frameworkVanilla を選択してください。
  • Select a variantTypeScript を選択してください。
% npm create vite@latest
✔ Project name: … miniapp-example
✔ Select a framework: › Vanilla
✔ Select a variant: › TypeScript
Scaffolding project in ・・・/miniapp-example...
Done. Now run:
cd miniapp-example
npm install
npm run dev
ヒント

ここではViteをツールとして利用し、ReactVue などのフレームワークを利用せずに説明していきますが、 各種フレームワークやメタフレームワーク (Next.jsNuxt など) と合わせて利用することもできます。

SDK の組み込み

まず、.npmrc ファイルを作成します。 .npmrc という名前のファイルをプロジェクトのルートディレクトリに作成し、以下の内容を追加してください。

@pocketsign:registry=https://repo.platform.p8n.app
//repo.platform.p8n.app/:_auth=<YOUR_BASIC_AUTH_STRING>

<YOUR_BASIC_AUTH_STRING> の部分は、以下のコマンドによって生成される値を入力してください。

echo -n "token-user:<YOUR_SDK_TOKEN>" | base64

<YOUR_SDK_TOKEN>の部分は、SDK 取得用トークンを入力してください。SDK 取得用トークンの取得方法はSDK 取得用トークンの作成を参照してください。

注意

実際のプロジェクトでは、.npmrc に SDK トークンを直接記載しないでください。 また、VCS にトークンが記録されないように注意してください。

保存したら、npm install @pocketsign/in-app-sdk を実行してパッケージに SDK をインストールします。

% npm install @pocketsign/in-app-sdk

added 19 packages, and audited 20 packages in 6s

5 packages are looking for funding
run `npm fund` for details

found 0 vulnerabilities

プロジェクトの package.json が以下のようになっていれば成功です。

{
"name": "miniapp-example",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
/* ... */
},
"devDependencies": {
/* ... */
},
"dependencies": {
"@pocketsign/in-app-sdk": "^x.y.z"
}
}

リソースを取得する

まず、デバッグユーザーの項を参照して、 デバッグユーザーの作成とサービスのサブスクリプションをしてください。その後得られるアクセストークンを保存しておいてください。

デバッグユーザーはモック環境でのみ利用可能なので、モック環境を利用します。 SDKのAPIバックエンドという機能を利用することで、通常のブラウザでの開発が可能です。

では、ユーザーの氏名のリソースを取得して表示する機能を実装します。

src ディレクトリの中に、新たに miniapp.ts を追加します。 以下のコードを追加してください。サービスIDはPlatformから確認できます。アクセストークンは先ほど保存した値です。

import {
createSDKInstance,
createApiBackend,
requestPermission,
readResourceRaw,
MergedSourceResources,
} from '@pocketsign/in-app-sdk'

const SERVICE_ID = '/* ここにサービスID */'
const ACCESS_TOKEN = '/* ここにアクセストークン */'

export async function setup(button: HTMLButtonElement, output: HTMLElement) {
const sdk = await createSDKInstance({
serviceId: SERVICE_ID,
backend: createApiBackend({ accessToken: ACCESS_TOKEN })
})

const onClick = async () => {
const expireAt = new Date()
expireAt.setHours(expireAt.getHours() + 1)

const requestResult = await requestPermission(sdk, [
{
resourceId: MergedSourceResources.fullName,
verbs: [{ verb: 'read' as const, term: 'temporary' as const, expireAt }]
}
])
if (requestResult.result === 'agree') {
const result = await readResourceRaw(sdk, { resourceId: MergedSourceResources.fullName })
if (result.result === 'success') {
const value = result.value === null ? null : JSON.parse(result.value)
output.textContent += `姓名: ${value}\n`
}
}
};
button.addEventListener('click', onClick);
}
注意

実際のプロジェクトでは、ソースコードにアクセストークンを直接記載しないでください。 また、VCS にトークンが記録されないように注意してください。

また、 src/main.ts を以下の内容に置き換えてください。

import { setup } from './miniapp.ts';

document.querySelector<HTMLDivElement>('#app')!.innerHTML = `
<div>
<button id="read" type="button">read name</button>
<p id="output"></p>
</div>
`;

setup(
document.querySelector<HTMLButtonElement>('#read')!,
document.querySelector<HTMLElement>('#output')!
);

その後、Platformで「基本4情報における氏名」のリソース (ID: 50f423aa-8ea8-4385-81a1-a7d8da1c4939) を READ 権限で要求するようにしてください。「最初に要求する」は無効で問題ありません。

リソース取得の動作確認

npm run devで開発サーバーを立ち上げ、立ち上がったサーバーにアクセスしてください。 表示された「read name」ボタンをタップすると、姓名がミニアプリに表示されます。

本番環境へのデプロイと動作確認

本番環境のサービスをPlatformで作成してください。モック環境のサービスと同じく「基本4情報における氏名」のリソース (ID: 50f423aa-8ea8-4385-81a1-a7d8da1c4939) を READ 権限で要求するようにしてください。

本番環境ではポケットサインアプリ内で動作させるため、APPバックエンドに変更します。 src/miniapp.ts を以下のように書き換えてください。

import {
createSDKInstance,
createAppBackend,
requestPermission,
readResourceRaw,
MergedSourceResources,
} from '@pocketsign/in-app-sdk'

const SERVICE_ID = '/* ここにサービスID */'

export async function setup(button: HTMLButtonElement, output: HTMLElement) {
const sdk = await createSDKInstance({
serviceId: SERVICE_ID,
backend: createAppBackend()
})

/* ... */
}

そうしたら、npm run buildでビルドを行って、生成物をデプロイしてください。 npm run preview -- --hostコマンドの実行とポートフォワーディングを行うツール(例:ngrok)を利用しても問題ありません。 ただし、HTTPSでデプロイされたサイトにアクセスできる必要があります。

Platformで確認できる起動リンクの節にあるQRコードをポケットサインアプリで読み取ると、デプロイしたミニアプリを起動できます。 起動後、表示された「read name」ボタンをタップすると、必要に応じて権限要求画面が表示され、姓名がミニアプリに表示されます。

ヒント

現在はAPPバックエンドをモック環境で試せません。 将来的にモック環境へ接続できるポケットサインアプリを公開予定です。

サーバーでのリソースの利用

今度は、リソースを表示するのではなく、サーバーへ送信する機能を実装します。 src/miniapp.ts を以下の内容に置き換えてください。

import {
createSDKInstance,
createAppBackend,
requestPermission,
readResourceWithSignature,
MergedSourceResources,
} from '@pocketsign/in-app-sdk'

const SERVICE_ID = '/* ここにサービスID */'

export async function setup(button: HTMLButtonElement, output: HTMLElement) {
const sdk = await createSDKInstance({
serviceId: SERVICE_ID,
backend: createAppBackend()
})

const onClick = async () => {
const expireAt = new Date()
expireAt.setHours(expireAt.getHours() + 1)

const requestResult = await requestPermission(sdk, [
{
resourceId: MergedSourceResources.fullName,
verbs: [{ verb: 'read' as const, term: 'temporary' as const, expireAt }]
}
])
if (requestResult.result === 'agree') {
const result = await readResourceWithSignature(sdk, { resourceId: MergedSourceResources.fullName })
if (result.result === 'success') {
await fetch('/name', { method: 'POST', body: result.value })
output.textContent += '送信しました\n'
}
}
};
button.addEventListener('click', onClick);
}
危険

readResourceRawではなくreadResourceWithSignatureを利用するように変更したことに注意してください。 サーバーへ値を送信する際は、必ずWithSignatureで終わる署名付き値を取得できるAPIを利用してください。 詳しくは署名付き値を参照してください。

では、サーバー側の実装をします。

npm install express を実行して express をインストールします。

% npm install express jsonwebtoken jwks-rsa

added 101 packages, and audited 123 packages in 2s

18 packages are looking for funding
run `npm fund` for details

found 0 vulnerabilities

api ディレクトリの中に、新たに index.js を追加します。 以下のコードを追加してください。

import express from 'express'
import jwt from 'jsonwebtoken'
import JwksClient from 'jwks-rsa'
import { MergedSourceResources } from '@pocketsign/in-app-sdk'

const SERVICE_ID = '/* ここにサービスID */'
const PORT = 3000

const jwksClient = JwksClient({
jwksUri: 'https://api.core.p8n.app/jwks'
})
const getKey = (header, callback) => {
jwksClient.getSigningKey(header.kid).then(
(key) => {
callback(null, key.getPublicKey());
},
(err) => {
callback(err)
}
)
}

const app = express()
app.use(express.text())

app.post('/name', (req, res, next) => {
// NOTE: 必ずaudienceの検証をしてください。
// 詳しくは「署名付き値」を参照してください。
jwt.verify(req.body, getKey, { audience: SERVICE_ID }, (err, decoded) => {
if (err) return next(err)

// NOTE: 必ずresource_idの検証をしてください。
// 詳しくは「署名付き値」を参照してください。
if (decoded.resource_id !== MergedSourceResources.fullName) {
return next(new Error('Different resource value received'))
}

console.log('氏名:', decoded.value !== null ? JSON.parse(decoded.value) : 'なし')
res.end()
})
})

app.use(express.static('dist'))

app.listen(PORT, () => {
console.log(`listening on port ${PORT}`)
})

通知の送信

プッシュ通知を送信する機能も実装します。 src/miniapp.ts を以下のように書き換えてください。

import {
createSDKInstance,
createAppBackend,
requestPermission,
readResourceWithSignature,
MergedSourceResources,
PushNotificationResourceId,
getSubscriptionIdWithSignature,
} from '@pocketsign/in-app-sdk'

/* ... */

export async function setup(button: HTMLButtonElement, notificationButton: HTMLButtonElement, output: HTMLElement) {
/* ... */
button.addEventListener('click', onClick);

const onNotificationButtonClick = async () => {
const requestResult = await requestPermission(sdk, [
{
resourceId: PushNotificationResourceId,
verbs: [{ verb: 'invoke' as const, term: 'always' as const }]
}
])
if (requestResult.result === 'agree') {
const result = await getSubscriptionIdWithSignature(sdk)
if (result.result === 'success') {
await fetch('/notification', { method: 'POST', body: result.subscriptionId })
output.textContent += '送信しました\n'
}
}
}
notificationButton.addEventListener('click', onNotificationButtonClick);
}

また、 src/main.ts を以下の内容に置き換えてください。

import { setup } from './mini-app.ts';

document.querySelector<HTMLDivElement>('#app')!.innerHTML = `
<div>
<button id="read" type="button">read name</button>
<button id="notification" type="button">send notification</button>
<p id="output"></p>
</div>
`;

setup(
document.querySelector<HTMLButtonElement>('#read')!,
document.querySelector<HTMLButtonElement>('#notification')!,
document.querySelector<HTMLElement>('#output')!
);

その後、Platformで「プッシュ通知を送るための権限」のリソース (ID: 3441d71b-8b11-44aa-886e-c46901f3c910) を INVOKE 権限で要求するようにしてください。「最初に要求する」は無効で問題ありません。

では、サーバー側の実装をします。api/index.js を以下のように書き換えてください。シークレットキーはPlatformで発行できます(シークレットキー)。

/* ... */

const SERVICE_ID = '/* ここにサービスID */'
const SECRET_KEY = '/* ここにシークレットキー */'
const PORT = 3000

/* ... */

app.post('/name', (req, res) => {
/* ... */
})

app.post('/notification', (req, res) => {
// NOTE: 必ずaudienceの検証をしてください。
// 詳しくは「署名付き値」を参照してください。
jwt.verify(req.body, getKey, { audience: SERVICE_ID }, (err, decoded) => {
if (err) return next(err)

const subscriptionId = decoded.subscription_id
if (!subscriptionId) {
return next(new Error("subscription_id doesn't exist"))
}

fetch(
'https://api.core.p8n.app/pocketsign.link.v1.ServiceService/CreateNotification',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${SECRET_KEY}`
},
body: JSON.stringify({
targetSubscriptionIds: [subscriptionId],
messageTemplate: 'push notification test'
})
}
)
.then((res) => res.json())
.then((res) => {
console.log('Notification', res)
})
.finally(() => {
res.end()
})
})
})

app.use(express.static('dist'))

app.listen(PORT, () => {
/* ... */
})
注意

実際のプロジェクトでは、ソースコードにシークレットキーを直接記載しないでください。 また、VCS にシークレットキーが記録されないように注意してください。

サーバーの動作確認

リソースを送信する機能と通知を送信する機能の動作確認をします。

先ほどと同じようにnpm run buildでビルドを行います。今度はサーバーのデプロイも必要です。 先ほどと同じく、node api/index.jsコマンドの実行とポートフォワーディングを行うツールを利用しても問題ありません。

Platformで確認できる起動リンクの節にあるQRコードをポケットサインアプリで読み取ると、デプロイしたミニアプリを起動できます。 今度はホーム画面から起動できます。 起動後、表示された「send notification」ボタンをタップすると、必要に応じて権限要求画面が表示され、サーバーへ通信送信リクエストが送られます。 サーバーではポケットサインのサーバーへプッシュ通知の送信要求を送ります。 そして、手元のポケットサインでプッシュ通知が表示されます。