defmodule LibWechat do
@moduledoc """
LibWechat - 微信 API Elixir 库
这是一个用于与微信 API 交互的 Elixir 库,提供了小程序、公众号等微信平台的功能接口。
## 使用方法
在你的模块中 `use LibWechat` 来获得所有微信 API 功能:
defmodule MyApp.Wechat do
use LibWechat, otp_app: :my_app
end
然后在配置文件中设置微信应用信息:
config :my_app, MyApp.Wechat,
appid: "your_app_id",
secret: "your_app_secret"
## 可用功能
- 认证管理:获取 access_token、小程序登录
- 小程序码:生成不限量小程序码
- 链接生成:URL Link、Scheme 码
- 消息推送:订阅消息发送
- 用户信息:获取手机号
- 安全检查:文本内容安全检测
## 启动
{:ok, _pid} = MyApp.Wechat.start_link()
## 示例
# 获取 access_token
{:ok, token_info} = MyApp.Wechat.get_access_token()
# 小程序登录
{:ok, session} = MyApp.Wechat.jscode_to_session("user_code")
# 生成小程序码
{:ok, qrcode} = MyApp.Wechat.get_unlimited_wxacode(token, payload)
更多详细使用说明请参考 [README.md](README.md) 文件。
"""
@external_resource "README.md"
defmacro __using__(opts) do
quote do
alias LibWechat.Core
alias LibWechat.Typespecs
@type ok_t(ret) :: {:ok, ret}
@type err_t() :: {:error, LibWechat.Error.t()}
def init(config) do
{:ok, config}
end
defoverridable init: 1
def child_spec(opts) do
%{
id: __MODULE__,
start: {__MODULE__, :start_link, [opts]},
type: :supervisor
}
end
def start_link(config \\ []) do
otp_app = unquote(opts[:otp_app])
{:ok, cfg} =
otp_app
|> Application.get_env(__MODULE__, config)
|> init()
LibWechat.Supervisor.start_link(__MODULE__, cfg)
end
defp delegate(method, args), do: apply(Core, method, [__MODULE__ | args])
@doc """
获取access_token
https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html
## Examples
iex> LibWechat.get_access_token()
{:ok, %{"access_token" => "xxx", "expires_in" => 7200}}
"""
@spec get_access_token() :: {:ok, Typespecs.dict()} | err_t()
def get_access_token, do: delegate(:get_access_token, [])
@doc """
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html
"""
@spec jscode_to_session(binary()) :: {:ok, Typespecs.dict()} | err_t()
def jscode_to_session(js_code), do: delegate(:jscode_to_session, [js_code])
@doc """
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/qr-code/wxacode.getUnlimited.html
## Examples
iex> LibWechat.get_unlimited_wxacode(token,
%{"scene" => "foo=bar",
"page" => "pages/index/index",
"width" => 430,
"auto_color" => false,
"line_color" => %{"r" => 0, "g" => 0, "b" => 0},
"is_hyaline" => false
}
)
{:ok, <<255, 216, ...>>}
"""
@spec get_unlimited_wxacode(binary(), Typespecs.dict()) :: {:ok, binary()} | err_t()
def get_unlimited_wxacode(token, payload) do
delegate(:get_unlimited_wxacode, [token, payload])
end
@doc """
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-link/urllink.generate.html
## Examples
iex> LibWechat.get_urllink(token,
%{
"path" => "pages/index/index",
"query" => "foo=bar",
"is_expire" => false,
"expire_type" => 0,
"expire_time" => 0
}
)
{:ok, %{
"errcode" => 0,
"errmsg" => "ok",
"url_link" => "https://wxaurl.cn/bz2LB4RMDVqq"
}}
"""
@spec get_urllink(binary(), Typespecs.dict()) :: {:ok, Typespecs.dict()} | err_t()
def get_urllink(token, payload) do
delegate(:get_urllink, [token, payload])
end
@doc """
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-scheme/urlscheme.generate.html
## Examples
iex> generate_scheme(token,
%{
"jump_wxa" => %{
"path" => "pages/index/index",
"query" => "foo=bar"
},
"is_expire" => false,
"expire_type" => 0,
"expire_time" => 0
}
)
{:ok, %{
"errcode" => 0,
"errmsg" => "ok",
"openlink" => "weixin://dl/business/?t=Akeatr890b"
}}
"""
@spec generate_scheme(binary(), Typespecs.dict()) :: {:ok, Typespecs.dict()} | err_t()
def generate_scheme(token, payload) do
delegate(:generate_scheme, [token, payload])
end
@doc """
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.send.html
## Examples
iex> subscribe_send(token, %{
"touser" => "OPENID",
"template_id" => "TEMPLATE_ID",
"page" => "index",
"miniprogram_state" => "developer",
"lang" => "zh_CN",
"data" => %{
"number01" => %{"value" => "339208499"},
"date01" => %{"value" => "2015年01月05日"},
"site01" => %{"value" => "TIT创意园"},
"site02" => %{"value" => "广州市新港中路397号"}
}
})
{:ok, %{
"errcode" => 0,
"errmsg" => "ok",
"msgid" => 294402298110051942
}}
"""
@spec subscribe_send(binary(), Typespecs.dict()) :: {:ok, Typespecs.dict()} | err_t()
def subscribe_send(token, payload) do
delegate(:subscribe_send, [token, payload])
end
@doc """
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/uniform-message/uniformMessage.send.html
## Examples
iex> LibWechat.uniform_send(token,
%{
"touser" => "OPENID",
"weapp_template_msg" => %{
"template_id" => "TEMPLATE_ID",
"page" => "index",
"form_id" => "FORMID",
"data" => %{
"keyword1" => %{"value" => "339208499"},
"keyword2" => %{"value" => "2015年01月05日"},
"keyword3" => %{"value" => "粤海喜来登酒店"},
"keyword4" => %{"value" => "广州市天河区天河路208号"}
},
"emphasis_keyword" => "keyword1.DATA"
},
"mp_template_msg" => %{
"appid" => "APPID ",
"template_id" => "TEMPLATE_ID",
"url" => "http://weixin.qq.com/download",
"miniprogram" => %{
"appid" => "xiaochengxuappid12345",
"pagepath" => "index?foo=bar"
},
"data" => %{
"first" => %{"value" => "恭喜你购买成功!", "color" => "#173177"},
"keyword1" => %{"value" => "巧克力", "color" => "#173177"},
"keyword2" => %{"value" => "39.8元", "color" => "#173177"},
"keyword3" => %{"value" => "2014年9月22日", "color" => "#173177"},
"remark" => %{"value" => "欢迎再次购买!", "color" => "#173177"}
}
}
})
{:ok, %{"errcode" => 0, "errmsg" => "ok"}}
"""
@deprecated "This API has been unsupported. For more details, please view https://developers.weixin.qq.com/community/develop/doc/000ae8d6348af08e7030bc2546bc01?blockType=1"
@spec uniform_send(binary(), Typespecs.dict()) :: {:ok, Typespecs.dict()} | err_t()
def uniform_send(token, body) do
delegate(:uniform_send, [token, body])
end
@doc """
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/phonenumber/phonenumber.getPhoneNumber.html
## Examples
iex> get_phone_number(token, code)
{:ok,
%{
"errcode":0,
"errmsg":"ok",
"phone_info": {
"phoneNumber":"xxxxxx",
"purePhoneNumber": "xxxxxx",
"countryCode": 86,
"watermark": {
"timestamp": 1637744274,
"appid": "xxxx"
}
}
}
}
"""
@spec get_phone_number(binary(), binary()) :: {:ok, Typespecs.dict()} | err_t()
def get_phone_number(token, code) do
delegate(:get_phone_number, [token, code])
end
@doc """
https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/sec-center/sec-check/msgSecCheck.html
## Examples
iex> payload = %{
"openid"=> "OPENID",
"scene"=> 1,
"version"=> 2,
"content"=> "hello world!"
}
iex> msg_sec_check(token, payload)
{
"errcode"=> 0,
"errmsg"=> "ok",
"result"=> %{
"suggest"=> "risky",
"label"=> 20001
},
"detail"=> [
%{
"strategy"=> "content_model",
"errcode"=> 0,
"suggest"=> "risky",
"label"=> 20006,
"prob"=> 90
},
%{
"strategy": "keyword",
"errcode": 0,
"suggest": "pass",
"label": 20006,
"level": 20,
"keyword": "命中的关键词1"
},
{
"strategy": "keyword",
"errcode": 0,
"suggest": "risky",
"label": 20006,
"level": 90,
"keyword": "命中的关键词2"
}
],
"trace_id": "60ae120f-371d5872-7941a05b"
}
"""
@spec msg_sec_check(binary(), Typespecs.dict()) :: {:ok, Typespecs.dict()} | err_t()
def msg_sec_check(token, payload) do
delegate(:msg_sec_check, [token, payload])
end
end
end
end