> For the complete documentation index, see [llms.txt](https://imtoken.gitbook.io/developers/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://imtoken.gitbook.io/developers/zh/products/webview/development-guide-for-imtoken-dapp.md).

# imToken DApp 开发指引

学习如何开发 DApp 并连接到 imToken。

## 介绍

本文档将以最简单易懂的方式指导你从头开始创建 DApp，并将你的 DApp 与 imToken 应用程序相连接。本文所使用的示例项目托管于 [GitHub (token-getting-started)](https://github.com/consenlabs/token-getting-started)，你可以 [安装 imToken 应用](https://token.im/download) 打开项目以预览开发过程中的变化。

imToken 应用在宿主环境与 DApp 之间的通信遵循 [EIP-1102](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1102.md) 协议，也完全兼容于 MetaMask。你也可以使用 MetaMask 调试自己的 DApp。

{% hint style="info" %}
想要了解更多的 RPC 接口，请看 [RPC 接口文档](/developers/zh/products/webview/rpcs.md)。
{% endhint %}

## 假设

此文档假设你已经拥有基础的 Web 开发知识，如 `HTML` / `CSS` / `JavaScript` 等，作为最佳实践，示例项目是基于 React 创建。

如果你完全不需要任何项目框架，仅想使用纯 `JavaScript` 开发，请参考我们的 [入门示例](https://github.com/consenlabs/token-getting-started/blob/master/pure/README.md)。

## 创建项目

输入 `npx create-next-app` 以创建基础的 React 项目，这是我们非常熟悉的最简化结构的 Web 应用，虽然，我们需要下载与安装一些 DApp 相关的依赖。

```
npm i @ethersproject/providers @web3-react/core @web3-react/injected-connector
```

`web3-react` 是适用于 React 框架的高层封装库，这可以帮我们屏蔽更多 RPC 接口的实现细节，仅以最简单的方式调用函数，同时还为我们提供了非常丰富的类型支持。

> 对于 Web3 与之相关类库的解释：
>
> DApp 的具体实现与你选择的类库是无关的，只要类库遵循 EIP 标准即可。imToken 环境内也不会为你注入类似于 `web3.js` 或是 `ethersjs` 等第三方库 (出于安全考量)，仅会添加用于连接的 Provider 信息。
>
> 如果你需要任何其他第三方库，请确保已将依赖已经安装并最终会打包至 Web App 的输出文件中。

现在我们只需要初始化 `Provider` 即可在组件中使用 `Hooks` 调用相关 RPC 接口。

增加 Provider 组件 (实际上这是 `React Context`) 到你的 React 项目根组件中，并添加 `getLibrary` 方法进行连接。

{% code title="pages/\_app.tsx" %}

```jsx
import { Web3ReactProvider } from '@web3-react/core'
import { Web3Provider } from '@ethersproject/providers'

const getLibrary = () => {
  const provider = (window as any).web3.currentProvider
  return new Web3Provider(provider)
}

<Web3ReactProvider getLibrary={getLibrary}>
  <Component {...pageProps} />
</Web3ReactProvider>
```

{% endcode %}

上述代码可以在 [pages/\_app.tsx](https://github.com/consenlabs/token-getting-started/blob/master/react/pages/_app.tsx) 文件中找到。

{% hint style="info" %}
我们还在示例项目中添加了基础的 UI 布局，这是为了保证用户预览时有较好的体验。如果不需要，你完全可以忽略它们。
{% endhint %}

## 连接到节点

当我们创建 Provider 后，可以尝试在页面中开始连接到节点：

```typescript
const injected = new InjectedConnector({
  supportedChainIds: [
    1, // Mainet
    3, // Ropsten
    4, // Rinkeby
    5, // Goerli
    42, // Kovan
  ],
})

const { activate, active, account } = useWeb3React<Web3Provider>()

const clickHandler = async () => {
  try {
    if (active) return alert('Already linked')
    await activate(injected, walletError => {
      if (walletError.message.includes('user_canceled')) {
        return alert('You canceled the operation, please refresh and try to reauthorize.')
      }
      alert(`Failed to connect: ${walletError.message}`)
    })
  } catch (err) {
    console.log(err)
    alert('Failed to connect Wallet.')
  }
}
```

调用`activate` 方法 (异步) 可以开始尝试连接，如果连接失败会抛出相关的错误信息，在用户接受响应后，连接将会被保存，同时 `account` 数据也会被自动更新，我们将会得到用户的账户地址。

![After authorization is complete, we get the user's address](https://1099326104-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MUvnj-TVDZBXlq-Q9JJ%2F-MYD5QNWzU8gdnuB73aC%2F-MYDTiPC3Yr5a20gCFTq%2Fguide-1%20\(1\).png?alt=media\&token=b83b0fc2-3cab-4678-9af6-3349af7cf996)

你可以在 `supportedChainIds` 中指定可支持的链 ID。上述代码可以在 [connector.tsx](https://github.com/consenlabs/token-getting-started/blob/master/react/libs/connector.tsx) 文件中找到。

## 请求签名

请求签名是 DApp 开发中非常关键的一部分，但通常你只需要学习了解请求签名方式中的一种，其他对于不同信息体的签名也能以此类推。在这里作为一个最简单的示例，我们尝试让用户签名一个文本信息 (`text message`)，如果我们成功将会得到一个由用户私钥签名的结果 (字符串)。

{% hint style="info" %}
在任何时候，你都可以通过签名结果来确认信息是否来自某个地址，这是签名的主要作用。
{% endhint %}

```typescript
const [result, setResult] = useState<string>('')
const { active, account, library } = useWeb3React<Web3Provider>()
const isConnected = useMemo(() => active && account, [account, active])

const clickHandler = async () => {
  if (!isConnected) return
  const signer = library.getSigner(account)
  try {
    const result = await signer.signMessage(MESSAGE)
    setResult(result)
  } catch (err) {
    if (err?.errorCode === 1001) {
      return alert('You canceled the operation.')
    }
    alert(err.message)
  }
}

```

我们可以通过 `account` 或 `active` 来确认当前是否已连接并已获取到用户的地址 (如果没有，重复上一步)，一旦连接确认，我们可以使用准备好的 `signMessage` 方法请求用户签名。

imToken 应用 (或其他兼容 EIP RPC 的钱包) 都会监听来自外部符合 EIP 规范的 RPC 调用，在这里我们使用 `signMessage` 方法屏蔽了 RPC 接口的调用细节，你可以粗略将此方法理解为 Web 应用中常见的 `HTTP` 上层封装，异步调用，返回 Promise 类型。

示例代码中核心内容很简单，只有 `signer.signMessage` 一句，其他均是处理错误相关信息。对于上诉所有示例代码，你可以在 [sign.tsx](https://github.com/consenlabs/token-getting-started/blob/master/react/libs/sign.tsx) 文件中找到。

## 其他

#### 直接 Clone 项目

如果你按文档指引查看代码仍旧感到困惑，可以直接将示例项目 Clone 到本地调试：&#x20;

```
git clone git@github.com:consenlabs/token-getting-started.git
```

在本地调试代码并尝试连接到钱包将有助于你理解 DApp 的工作原理。

#### 直接预览项目

作为更简单的方式，你可以直接在 imToken 应用中打开 `https://token-example-react.vercel.app/` 预览此项目，或是使用 imToken 应用扫描下方二维码。

![](https://1099326104-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MUvnj-TVDZBXlq-Q9JJ%2F-MYEbbaOmrFAL7tCy8wC%2F-MYEcMtBfL-ilMMQfsrH%2Fguide-2%20\(3\).png?alt=media\&token=146851a1-555e-4295-a9fc-61fa1aa675d1)

#### 帮助

遇到示例项目代码过时或是其他难以解决的技术问题？请在开发者社区中 [创建一个讨论](https://github.com/consenlabs/webview/discussions/new)。
