├── .gitignore
├── LICENSE
├── README.md
├── README_en.md
├── SECURITY.md
├── images
├── demo.PNG
├── server_diagram.PNG
└── server_diagram_en.PNG
├── index.js
├── index.ts
├── package.json
├── public
└── js
│ ├── demo.js
│ └── demo.ts
├── tsconfig.json
├── types
└── wechat.d.ts
└── views
└── index.html
/.gitignore:
--------------------------------------------------------------------------------
1 | *.log
2 | node_modules
3 | .vscode
4 | .DS_Store
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Microsoft Corporation. All rights reserved.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [English version](README_en.md)
2 |
3 | 本教程将覆盖了基本的在使用[微信JSSDK](https://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html)的网页上运用TypeScript的例子。
4 |
5 | # 开始之前
6 |
7 | 1. 安装[node.js](https://nodejs.org/en/download/)。
8 |
9 | 1. 拥有/申请网页将使用的域名以及能够使用Node.js的服务器。可参照[Create a Node.js Application on Web App](https://docs.microsoft.com/en-us/azure/app-service-web/app-service-web-get-started-nodejs)文档使用Azure。
10 |
11 | 2. 完成微信开发文档[步骤一:绑定域名](https://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E6.AD.A5.E9.AA.A4.E4.B8.80.EF.BC.9A.E7.BB.91.E5.AE.9A.E5.9F.9F.E5.90.8D)。如果没有自己的公众号,可注册并使用微信[测试号](https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login)。记录下自己的appId, appsecret以及将使用的host URL。
12 |
13 | # 搭建node.js/express后台
14 |
15 | ## 初始
16 |
17 | 建立一个新的npm package,
18 |
19 | ```
20 | mkdir wxapp
21 | cd wxapp
22 | npm init
23 | ```
24 |
25 | 在生成的`package.json`的`scripts`中添加以下scripts,
26 |
27 | ```
28 | "scripts": {
29 | "start": "node index.js",
30 | "build-ts": "node ./node_modules/typescript/bin/tsc"
31 | },
32 | ```
33 |
34 | 安装需要的packages(express, ejs, request以及sha1),
35 |
36 | ```
37 | npm install --save express ejs request sha1
38 | ```
39 |
40 | 安装TypeScript以及之前安装的packages的类型定义。
41 |
42 | ```
43 | npm install --save-dev typescript @types/node @types/express @types/request @types/sha1
44 | ```
45 |
46 | 由于暂时[DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped)中并没有JSSDK相关的类型定义文件(.d.ts),请将本项目中的`types`文件夹(包含类型定义文件[wechat.d.ts](types/wechat.d.ts))复制到根目录(`wxapp`)中以便TypeScript获取JSSDK的类型定义。
47 |
48 | ## 配置TypeScript
49 |
50 | 在`wxapp`根目录下添加TypeScript配置文件`tsconfig.json`,
51 |
52 | ```js
53 | {
54 | "compilerOptions": {
55 | "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
56 | "module": "commonjs", /* Specify module code generation: 'commonjs', 'amd', 'system', 'umd' or 'es2015'. */
57 | "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
58 | }
59 | }
60 | ```
61 |
62 | 可以根据项目的需求自行添加[其他编译选项](https://www.typescriptlang.org/docs/handbook/compiler-options.html),比如`strict`。
63 |
64 | ## 获取jsapi_ticket
65 |
66 | 对应[通过config接口注入权限验证配置](https://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E6.AD.A5.E9.AA.A4.E4.B8.89.EF.BC.9A.E9.80.9A.E8.BF.87config.E6.8E.A5.E5.8F.A3.E6.B3.A8.E5.85.A5.E6.9D.83.E9.99.90.E9.AA.8C.E8.AF.81.E9.85.8D.E7.BD.AE)文档,调用微信JSSDK需要在自己的服务器后台向微信服务器获取jsapi_ticket并在前端通过`wx.config`进行验证。大致实现流程,
67 |
68 |
69 |
70 |
71 |
72 | 在根目录添加后台的初始文件`index.ts`,
73 |
74 | ```ts
75 | import * as express from "express";
76 | import * as request from "request";
77 | import sha1 = require("sha1");
78 |
79 | let app = express();
80 |
81 | // Insert metadata
82 | let appId = ''; // Insert your appId
83 | let appsecret = ''; // insert your appsecret
84 | let url = ''; // insert host url, e.g. http://wxapp.azurewebsites.net/
85 | let nonceStr = ''; // insert any string
86 |
87 | // define an interface containing params for wx.config
88 | interface configObj {
89 | appId: string,
90 | timestamp: string,
91 | nonceStr: string,
92 | signature: string
93 | }
94 |
95 | // handshake with WeChat server and get signature for wx.config
96 | function getWXConfig(cb) {
97 | request.get('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='+appId+'&secret='+appsecret, (err, res, body) => {
98 | request.get('https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token='+JSON.parse(body).access_token+'&type=jsapi', (err, res, body) => {
99 | let ticket = JSON.parse(body).ticket;
100 | let o: configObj = {
101 | appId: appId,
102 | nonceStr: nonceStr,
103 | timestamp: new Date().getTime() / 1000 + '',
104 | signature: ''
105 | };
106 | o.signature = sha1('jsapi_ticket='+ticket+'&noncestr='+o.nonceStr+'×tamp='+o.timestamp+'&url='+url).toString();
107 | cb(o);
108 | });
109 | });
110 | }
111 |
112 | app.engine('.html', require('ejs').__express); // set up ejs as view engine
113 | app.set('views', __dirname + '/views'); // set views dir
114 | app.set('view engine', 'html'); // use .html for ejs files
115 | app.use(express.static('public')) // expose assets in /public
116 | app.get('/', function (req, res) {
117 | getWXConfig(config => {
118 | // handshake with WeChat server and render index.html with the returned signature
119 | res.render('index', {
120 | appId: config.appId,
121 | timestamp: config.timestamp,
122 | nonceStr: config.nonceStr,
123 | signature: config.signature,
124 | });
125 | })
126 | });
127 | app.listen(8080);
128 |
129 | ```
130 |
131 | 在`index.ts`中修改并填入自己的appId等等参数,
132 | ```ts
133 | // Insert metadata
134 | let appId = ''; // Insert your appId
135 | let appsecret = ''; // insert your appsecret
136 | let url = ''; // insert host url, e.g. http://wxapp.azurewebsites.net/
137 | let nonceStr = 'hellotypescript'; // insert any string
138 | ```
139 |
140 | 建立的node.js+express后台会通过`getWXConfig`向微信服务器[获取jsapi_ticket](https://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E8.8E.B7.E5.8F.96api_ticket),并将[wx.config](https://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E6.AD.A5.E9.AA.A4.E4.B8.89.EF.BC.9A.E9.80.9A.E8.BF.87config.E6.8E.A5.E5.8F.A3.E6.B3.A8.E5.85.A5.E6.9D.83.E9.99.90.E9.AA.8C.E8.AF.81.E9.85.8D.E7.BD.AE)所需的参数通过ejs渲染(`res.render(...)`)至客户端页面。
141 |
142 | 在`index.ts`中已定义将后台推至客户端的文件放入`/views`(包含所有需要ejs渲染的`html`文件)以及`/public`(其余的文件)文件夹。之后的步骤将覆盖前端的页面。
143 | ``` ts
144 | app.set('views', __dirname + '/views'); // set views dir
145 | app.use(express.static('public')) // expose assets in /public
146 | ```
147 |
148 | # 客户端页面
149 |
150 | ## index.html
151 |
152 | 在根目录下建立`views`文件夹并在其中添加`index.html`(推至客户端的主页),
153 |
154 | ```html
155 |
156 |
157 |
158 |
159 | WeChat TypeScript sample
160 |
161 |
162 |
163 |
210 |
211 |
212 |
213 | ```
214 |
215 | `index.html`中引入了微信JSSDK(`http://res.wx.qq.com/open/js/jweixin-1.0.0.js`)以及将在客户端实现的简单的demo(`/js/demo.js`)。嵌入的JavaScript包含了之前渲染的`getWXConfig`提供的讯息并通过`wx.config`注入权限验证配置。
216 |
217 | ## demo.ts
218 |
219 | 在根目录下建立`public/js`文件夹,并在其中添加`demo.ts`,
220 |
221 | ```ts
222 | wx.ready(() => {
223 | // open specifc location on map
224 | wx.openLocation({
225 | latitude: 0,
226 | longitude: 0,
227 | name: '',
228 | address: '',
229 | scale: 1,
230 | infoUrl: ''
231 | });
232 | })
233 |
234 | wx.error((err) => alert(err));
235 | ```
236 |
237 | 在这个简化的例子中,我们仅使用`wx.openLocation`打开地图,但在`demo.ts`中你可以尝试使用任何在`JsApiList`中申请的API。
238 |
239 | # 生成与部署
240 |
241 | 将`.ts`文件编译成`.js`,
242 |
243 | ```
244 | npm run build-ts
245 | ```
246 |
247 | 部署至服务器。
248 |
249 | 将页面所在的网址转换成二维码,打开微信扫一扫便可看到成果。
250 |
251 |
252 |
253 |
254 |
--------------------------------------------------------------------------------
/README_en.md:
--------------------------------------------------------------------------------
1 | [中文版](README.md) (Chinese Version of this walkthrough)
2 |
3 | This tutorial covers a basic sample using [WeChat JSSDK](https://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html) and TypeScript together.
4 |
5 | # Before you start
6 |
7 | 1. Install [node.js](https://nodejs.org/en/download/).
8 |
9 | 1. Get your own domain and node.js server. See [Create a Node.js Application on Web App](https://docs.microsoft.com/en-us/azure/app-service-web/app-service-web-get-started-nodejs) for using Azure.
10 |
11 | 2. Finish [step 1 - binding domain name](https://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E6.AD.A5.E9.AA.A4.E4.B8.80.EF.BC.9A.E7.BB.91.E5.AE.9A.E5.9F.9F.E5.90.8D). If you don't have an official WeChat account, you can apply for a [test account](https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login). Keep your appId, appsecret and host URL at hand.
12 |
13 | # Set up node.js/express
14 |
15 | ## Initial steps
16 |
17 | Create a new package,
18 |
19 | ```
20 | mkdir wxapp
21 | cd wxapp
22 | npm init
23 | ```
24 |
25 | In `scripts` in `package.json`, add,
26 |
27 | ```
28 | "scripts": {
29 | "start": "node index.js",
30 | "build-ts": "node ./node_modules/typescript/bin/tsc"
31 | },
32 | ```
33 |
34 | Install dependencies (express, ejs, request, and sha1),
35 |
36 | ```
37 | npm install --save express ejs request sha1
38 | ```
39 |
40 | Install TypeScript and type definition files for installed packages,
41 |
42 | ```
43 | npm install --save-dev typescript @types/node @types/express @types/request @types/sha1
44 | ```
45 |
46 | Since [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped) does not have type definitions for WeChat JSSDK at the mement , copy the `types` folder containing [wechat.d.ts](/types/wechat.d.ts) to the project root folder (`wxapp`).
47 |
48 | ## Configure TypeScript
49 |
50 | Add TypeScript configuration file `tsconfig.json` under the project root folder,
51 |
52 | ```js
53 | {
54 | "compilerOptions": {
55 | "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
56 | "module": "commonjs", /* Specify module code generation: 'commonjs', 'amd', 'system', 'umd' or 'es2015'. */
57 | "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
58 | }
59 | }
60 | ```
61 |
62 | You can add [other compiler flags](https://www.typescriptlang.org/docs/handbook/compiler-options.html) (e.g. `strict`) based on your own need.
63 |
64 | ## Get jsapi_ticket
65 |
66 | According to [WeChat documentation](https://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E6.AD.A5.E9.AA.A4.E4.B8.89.EF.BC.9A.E9.80.9A.E8.BF.87config.E6.8E.A5.E5.8F.A3.E6.B3.A8.E5.85.A5.E6.9D.83.E9.99.90.E9.AA.8C.E8.AF.81.E9.85.8D.E7.BD.AE), using WeChat JSSDK requires getting jsapi_ticket from WeChat server on our server side and then using `wx.config` to get API permission on the cliend side. A rough flow looks like below,
67 |
68 |
69 |
70 |
71 |
72 | Add `index.ts` in the root folder,
73 |
74 | ```ts
75 | import * as express from "express";
76 | import * as request from "request";
77 | import sha1 = require("sha1");
78 |
79 | let app = express();
80 |
81 | // Insert metadata
82 | let appId = ''; // Insert your appId
83 | let appsecret = ''; // insert your appsecret
84 | let url = ''; // insert host url, e.g. http://wxapp.azurewebsites.net/
85 | let nonceStr = ''; // insert any string
86 |
87 | // define an interface containing params for wx.config
88 | interface configObj {
89 | appId: string,
90 | timestamp: string,
91 | nonceStr: string,
92 | signature: string
93 | }
94 |
95 | // handshake with WeChat server and get signature for wx.config
96 | function getWXConfig(cb) {
97 | request.get('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='+appId+'&secret='+appsecret, (err, res, body) => {
98 | request.get('https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token='+JSON.parse(body).access_token+'&type=jsapi', (err, res, body) => {
99 | let ticket = JSON.parse(body).ticket;
100 | let o: configObj = {
101 | appId: appId,
102 | nonceStr: nonceStr,
103 | timestamp: new Date().getTime() / 1000 + '',
104 | signature: ''
105 | };
106 | o.signature = sha1('jsapi_ticket='+ticket+'&noncestr='+o.nonceStr+'×tamp='+o.timestamp+'&url='+url).toString();
107 | cb(o);
108 | });
109 | });
110 | }
111 |
112 | app.engine('.html', require('ejs').__express); // set up ejs as view engine
113 | app.set('views', __dirname + '/views'); // set views dir
114 | app.set('view engine', 'html'); // use .html for ejs files
115 | app.use(express.static('public')) // expose assets in /public
116 | app.get('/', function (req, res) {
117 | getWXConfig(config => {
118 | // handshake with WeChat server and render index.html with the returned signature
119 | res.render('index', {
120 | appId: config.appId,
121 | timestamp: config.timestamp,
122 | nonceStr: config.nonceStr,
123 | signature: config.signature,
124 | });
125 | })
126 | });
127 | app.listen(8080);
128 |
129 | ```
130 |
131 | Fill in your appId and other metadata in `index.ts`,
132 |
133 | ```ts
134 | // Insert metadata
135 | let appId = ''; // Insert your appId
136 | let appsecret = ''; // insert your appsecret
137 | let url = ''; // insert host url, e.g. http://wxapp.azurewebsites.net/
138 | let nonceStr = 'hellotypescript'; // insert any string
139 | ```
140 |
141 | Our server will [get jsapi_ticket](https://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E8.8E.B7.E5.8F.96api_ticket) from WeChat server through `getWXConfig`, and render the signature for [wx.config](https://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E6.AD.A5.E9.AA.A4.E4.B8.89.EF.BC.9A.E9.80.9A.E8.BF.87config.E6.8E.A5.E5.8F.A3.E6.B3.A8.E5.85.A5.E6.9D.83.E9.99.90.E9.AA.8C.E8.AF.81.E9.85.8D.E7.BD.AE) in client side html through ejs.
142 |
143 | Within `index.ts`, we've defined our client side files to be stored in `/views` (`html` to be rendered by ejs) and `/public` (other files). The next step will cover client side pages.
144 |
145 | ``` ts
146 | app.set('views', __dirname + '/views'); // set views dir
147 | app.use(express.static('public')) // expose assets in /public
148 | ```
149 |
150 | # Client side pages
151 |
152 | ## index.html
153 |
154 | Create `views` folder under the root folder and add `index.html`,
155 |
156 | ```html
157 |
158 |
159 |
160 |
161 | WeChat TypeScript sample
162 |
163 |
164 |
165 |
212 |
213 |
214 |
215 | ```
216 |
217 | `index.html` includes the JSSDK (`http://res.wx.qq.com/open/js/jweixin-1.0.0.js`) and a simple demo (`/js/demo.js`). The embedded JavaScript includes rendered signature from `getWXConfig` and uses `wx.config` to get API permission from WeChat.
218 |
219 | ## demo.ts
220 |
221 | Create `public/js` folder under the root folder, and add `demo.ts`,
222 |
223 | ```ts
224 | wx.ready(() => {
225 | // open specifc location on map
226 | wx.openLocation({
227 | latitude: 0,
228 | longitude: 0,
229 | name: '',
230 | address: '',
231 | scale: 1,
232 | infoUrl: ''
233 | });
234 | })
235 |
236 | wx.error((err) => alert(err));
237 | ```
238 |
239 | In this simple demo, we only use `wx.openLocation` to open a map, but you can try calling any API from `JsApiList` in `demo.ts`.
240 |
241 | # Build and deploy
242 |
243 | Transpile `.ts` files to `.js`,
244 |
245 | ```
246 | npm run build-ts
247 | ```
248 |
249 | Deploy the project to server.
250 |
251 | After deployment, translate your URL to QR code and open 微信扫一扫 to see the demo in action.
252 |
253 |
254 |
255 |
256 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Security
4 |
5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
6 |
7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
8 |
9 | ## Reporting Security Issues
10 |
11 | **Please do not report security vulnerabilities through public GitHub issues.**
12 |
13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
14 |
15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
16 |
17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
18 |
19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
20 |
21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
22 | * Full paths of source file(s) related to the manifestation of the issue
23 | * The location of the affected source code (tag/branch/commit or direct URL)
24 | * Any special configuration required to reproduce the issue
25 | * Step-by-step instructions to reproduce the issue
26 | * Proof-of-concept or exploit code (if possible)
27 | * Impact of the issue, including how an attacker might exploit the issue
28 |
29 | This information will help us triage your report more quickly.
30 |
31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
32 |
33 | ## Preferred Languages
34 |
35 | We prefer all communications to be in English.
36 |
37 | ## Policy
38 |
39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
40 |
41 |
42 |
--------------------------------------------------------------------------------
/images/demo.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/TypeScript-WeChat-Starter/51e9a265828efd3140b162445084374604f2f72f/images/demo.PNG
--------------------------------------------------------------------------------
/images/server_diagram.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/TypeScript-WeChat-Starter/51e9a265828efd3140b162445084374604f2f72f/images/server_diagram.PNG
--------------------------------------------------------------------------------
/images/server_diagram_en.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/TypeScript-WeChat-Starter/51e9a265828efd3140b162445084374604f2f72f/images/server_diagram_en.PNG
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | const express = require("express");
4 | const request = require("request");
5 | const sha1 = require("sha1");
6 | let app = express();
7 | // Insert metadata
8 | let appId = ''; // Insert your appId
9 | let appsecret = ''; // insert your appsecret
10 | let url = ''; // insert host url, e.g. http://wxapp.azurewebsites.net/
11 | let nonceStr = ''; // insert any string
12 | // handshake with WeChat server and get signature for wx.config
13 | function getWXConfig(cb) {
14 | request.get('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' + appId + '&secret=' + appsecret, (err, res, body) => {
15 | request.get('https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' + JSON.parse(body).access_token + '&type=jsapi', (err, res, body) => {
16 | let ticket = JSON.parse(body).ticket;
17 | let o = {
18 | appId: appId,
19 | nonceStr: nonceStr,
20 | timestamp: new Date().getTime() / 1000 + '',
21 | signature: ''
22 | };
23 | o.signature = sha1('jsapi_ticket=' + ticket + '&noncestr=' + o.nonceStr + '×tamp=' + o.timestamp + '&url=' + url).toString();
24 | cb(o);
25 | });
26 | });
27 | }
28 | app.engine('.html', require('ejs').__express); // set up ejs as view engine
29 | app.set('views', __dirname + '/views'); // set views dir
30 | app.set('view engine', 'html'); // use .html for ejs files
31 | app.use(express.static('public')); // expose assets in /public
32 | app.get('/', function (req, res) {
33 | getWXConfig(config => {
34 | // handshake with WeChat server and render index.html with the returned signature
35 | res.render('index', {
36 | appId: config.appId,
37 | timestamp: config.timestamp,
38 | nonceStr: config.nonceStr,
39 | signature: config.signature,
40 | });
41 | });
42 | });
43 | app.listen(8080);
44 |
--------------------------------------------------------------------------------
/index.ts:
--------------------------------------------------------------------------------
1 | import * as express from "express";
2 | import * as request from "request";
3 | import sha1 = require("sha1");
4 |
5 | let app = express();
6 |
7 | // Insert metadata
8 | let appId = ''; // Insert your appId
9 | let appsecret = ''; // insert your appsecret
10 | let url = ''; // insert host url, e.g. http://wxapp.azurewebsites.net/
11 | let nonceStr = ''; // insert any string
12 |
13 | // define an interface containing params for wx.config
14 | interface configObj {
15 | appId: string,
16 | timestamp: string,
17 | nonceStr: string,
18 | signature: string
19 | }
20 |
21 | // handshake with WeChat server and get signature for wx.config
22 | function getWXConfig(cb) {
23 | request.get('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='+appId+'&secret='+appsecret, (err, res, body) => {
24 | request.get('https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token='+JSON.parse(body).access_token+'&type=jsapi', (err, res, body) => {
25 | let ticket = JSON.parse(body).ticket;
26 | let o: configObj = {
27 | appId: appId,
28 | nonceStr: nonceStr,
29 | timestamp: new Date().getTime() / 1000 + '',
30 | signature: ''
31 | };
32 | o.signature = sha1('jsapi_ticket='+ticket+'&noncestr='+o.nonceStr+'×tamp='+o.timestamp+'&url='+url).toString();
33 | cb(o);
34 | });
35 | });
36 | }
37 |
38 | app.engine('.html', require('ejs').__express); // set up ejs as view engine
39 | app.set('views', __dirname + '/views'); // set views dir
40 | app.set('view engine', 'html'); // use .html for ejs files
41 | app.use(express.static('public')) // expose assets in /public
42 | app.get('/', function (req, res) {
43 | getWXConfig(config => {
44 | // handshake with WeChat server and render index.html with the returned signature
45 | res.render('index', {
46 | appId: config.appId,
47 | timestamp: config.timestamp,
48 | nonceStr: config.nonceStr,
49 | signature: config.signature,
50 | });
51 | })
52 | });
53 | app.listen(8080);
54 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "wechat-typescript-sample",
3 | "description": "Sample for developing with wechat JSSDK and TypeScript",
4 | "version": "0.0.1",
5 | "private": true,
6 | "license": "MIT",
7 | "author": "Microsoft",
8 | "engines": {
9 | "node": ">=6.9.1"
10 | },
11 | "scripts": {
12 | "start": "node index.js",
13 | "build-ts": "node ./node_modules/typescript/bin/tsc"
14 | },
15 | "dependencies": {
16 | "ejs": "^2.5.6",
17 | "express": "^4.15.2",
18 | "request": "^2.81.0",
19 | "sha1": "^1.1.1"
20 | },
21 | "devDependencies": {
22 | "@types/express": "^4.0.35",
23 | "@types/node": "^7.0.18",
24 | "@types/request": "2.0.7",
25 | "@types/sha1": "^1.1.0",
26 | "typescript": "^2.3.2"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/public/js/demo.js:
--------------------------------------------------------------------------------
1 | wx.ready(() => {
2 | // open specifc location on map
3 | wx.openLocation({
4 | latitude: 0,
5 | longitude: 0,
6 | name: '',
7 | address: '',
8 | scale: 1,
9 | infoUrl: ''
10 | });
11 | });
12 | wx.error((err) => alert(err));
13 |
--------------------------------------------------------------------------------
/public/js/demo.ts:
--------------------------------------------------------------------------------
1 | wx.ready(() => {
2 | // open specifc location on map
3 | wx.openLocation({
4 | latitude: 0,
5 | longitude: 0,
6 | name: '',
7 | address: '',
8 | scale: 1,
9 | infoUrl: ''
10 | });
11 | })
12 |
13 | wx.error((err) => alert(err));
14 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
4 | "module": "commonjs", /* Specify module code generation: 'commonjs', 'amd', 'system', 'umd' or 'es2015'. */
5 | "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
6 | }
7 | }
--------------------------------------------------------------------------------
/types/wechat.d.ts:
--------------------------------------------------------------------------------
1 | declare namespace wx {
2 | function addCard(a: any): any;
3 | function checkJsApi(a: any): any;
4 | function chooseCard(a: any): any;
5 | function chooseImage(a: any): any;
6 | function chooseWXPay(a: any): void;
7 | function closeWindow(a: any): void;
8 | function config(a: any): any;
9 | function downloadImage(a: any): void;
10 | function downloadVoice(a: any): void;
11 | function error(a: any): void;
12 | function getLocation(a: any): any;
13 | function getNetworkType(a: any): any;
14 | function hideAllNonBaseMenuItem(a: any): void;
15 | function hideMenuItems(a: any): void;
16 | function hideOptionMenu(a: any): void;
17 | function onMenuShareAppMessage(a: any): void;
18 | function onMenuShareQQ(a: any): void;
19 | function onMenuShareQZone(a: any): void;
20 | function onMenuShareTimeline(a: any): void;
21 | function onMenuShareWeibo(a: any): void;
22 | function onVoicePlayEnd(a: any): void;
23 | function onVoiceRecordEnd(a: any): void;
24 | function openCard(a: any): void;
25 | function openLocation(a: any): void;
26 | function openProductSpecificView(a: any): void;
27 | function pauseVoice(a: any): void;
28 | function playVoice(a: any): void;
29 | function previewImage(a: any): void;
30 | function ready(a: any): void;
31 | function scanQRCode(a: any): any;
32 | function showAllNonBaseMenuItem(a: any): void;
33 | function showMenuItems(a: any): void;
34 | function showOptionMenu(a: any): void;
35 | function startRecord(a: any): void;
36 | function stopRecord(a: any): void;
37 | function stopVoice(a: any): void;
38 | function translateVoice(a: any): void;
39 | function uploadImage(a: any): void;
40 | function uploadVoice(a: any): void;
41 | }
42 |
--------------------------------------------------------------------------------
/views/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | WeChat TypeScript sample
6 |
7 |
8 |
9 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------