以下先容采取DeWeb调用微信扫一扫的详细实现。
一、概述DeWeb是一个可以直接将Delphi程序快速转换为网页运用的工具!
不理解的朋友请先浏览DeWeb——Delphi开拓Web运用 - 入门篇

或加QQ群120283369,密码pascal
采取调用微信扫一扫方案
优点:识别速率快,准确率高
缺陷:仅支持在微信环境中调用
演示(请在微信中打开):https://www.delphibbs.com/qrtest
视频加载中...
二、基本思路紧张思路是将自己的URL作为参数调用微信扫一扫运用(实在也是一个URL),等这个运用扫描完成后将扫描结果作为参数打开原来的URL
1、创建一个主调用运用,比如为qrtest,直接打开的URL为https://www.delphibbs.com/qrtest,以下称主调用URL
2、创建一个扫一扫运用,比如为scan,直接打开的URL为https://www.delphibbs.com/scan,以下称扫一扫URL
3、在主调用运用界面增加一个按钮,打开新网址:{扫一扫URL}?redirect_uri={主调用URL},类似:
https://www.delphibbs.com/scan?redirect_uri=https://www.delphibbs.com/qrtest
3、扫一扫运用启动后自动调用微信扫一扫,当扫描成功后,将结果作为参数打开主调用URL,网址:{主调用URL}?{扫描结果},类似:
https://www.delphibbs.com/qrtest?Absd234DSF
三、编程实现1、准备好"大众号
(1)准备域名和做事器
购买域名、域名备案、购买云做事器(轻量运用做事器就可以)、将域名指向云做事器IP
(2)申请微信"大众年夜众号,取得开拓者ID(AppID)和开拓者密码(AppSecret)
(3)将域名所在运做事器的IP加入白名单
(4)申请微信扫一扫权限
(5)设置JS接口安全域名
把稳:JS接口安全域名设置时
只能利用默认端口,不能利用其他端口须要下载一个验证文件在做事器主目录,也便是DeWebServer.exe同一目录域名不须要前面的https:// 或 http://不要利用子域名,如yz.delphibbs.com2、创建主调用运用
(1)创建(推举复制)一个普通DeWeb运用
(2)设置为移动模式,在Form1的OnMouseUp中设置
procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);begin dwSetMobileMode(Self,400,900);end;
(3)拖放一个TButton,Name为B1;拖放一个TMemo,Name为M1
(4)在OnShow事宜中设置取得的参数。该参数应为扫一扫的结果
procedure TForm1.FormShow(Sender: TObject);var sParams : string;begin // sParams := dwGetProp(Self,'params'); // if sParams ='' then begin M1.Lines.Text := '.........'; end else begin M1.Lines.Text := sParams; end;end;
(5)在B1的OnClick事宜中实行以下代码
procedure TForm1.B1Click(Sender: TObject);begin dwOpenUrl(Self,'https://www.delphibbs.com/scan?redirect_uri=https://www.delphibbs.com/qrtest','_self')end;
3、创建扫一扫运用
(1)创建一个移动端DeWeb运用
(2)增加一些基本函数
procedure TForm1.wcGetAccessToken;var Url : string; joRes : Variant;begin //根据接口URL和 _AppID, _AppSecret 天生终极接口 URL Url := System.SysUtils.Format(_TokenUrl, [_AppID, _AppSecret]); //通过get取得返回值 gsResp := GetMethod(Url, 1); //如果调试模式,则显示结果 if gbDebug then begin Memo1.Lines.Add('wcGetAccessToken:'#13+gsResp); end;{ //解析返回的JSON字符串,取得access_token值 J := TJSONObject.ParseJSONValue(gsResp) as TJSONObject; try if J.Count > 0 then begin gsAccessToken := J.GetValue('access_token').Value; giExpires_IN := J.GetValue('expires_in').Value.ToInteger; end; finally J.Free; end;} joRes := _json(gsResp); if joRes <> unassigned then begin if joRes.Exists('access_token') and joRes.Exists('expires_in') then begin gsAccessToken := joRes.access_token; giExpires_IN := joRes.expires_in; end; end;end;procedure TForm1.wcGetJsapi_ticket;var Url : string; joRes : Variant;begin //根据gsAccessToken得到URL Url := System.SysUtils.Format( 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi', [gsAccessToken]); //get取得结果 gsResp := GetMethod(Url, 1); //如果调试模式,则显示结果 if gbDebug then begin Memo1.Lines.Add('wcGetJsapi_ticket:'#13+gsResp); end; //取值 joRes := _json(gsResp); if joRes <> unassigned then begin if joRes.Exists('ticket') then begin gsJsapi_ticket := joRes.ticket; end; end;end;function TForm1.wcSha1(input:string):string;var temp:tidbytes;begin with tidhashsha1.create do try result := LowerCase(HashBytesAsHex(TidBytes(Bytesof(input)))); //result:=HashStringAsHex(input); finally free; end;end;// 日期转Unix韶光戳function DateTimeToUnix(const AValue: TDateTime): Int64;begin Result := System.DateUtils.DateTimeToUnix(AValue) - 8 60 60;end;//把稳事变://1、署名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。//2、署名用的url必须是调用JS接口页面的完全URL。//3、出于安全考虑,开拓者必须在做事器端实现署名的逻辑。function TForm1.wcGetSignature(Ajsapi_ticket,Anoncestr,ATimestamp,Aurl:string):string;var sData : String;begin sData := Format('jsapi_ticket=%s&noncestr=%s×tamp=%s&url=%s', [Ajsapi_ticket,Anoncestr,ATimestamp,Aurl]); // Result := wcSha1(sData);end;// 日期转Unix韶光戳function dwDateTimeToUnix(const AValue: TDateTime): Int64;begin Result := System.DateUtils.DateTimeToUnix(AValue) - 8 60 60;end;function TForm1.GetMethod(Url: String; Max: Integer): String;var RespData : TStringStream; HTTP : TIdHTTP; SSL : TIdSSLIOHandlerSocketOpenSSL;begin RespData := TStringStream.Create('', TEncoding.UTF8); SSL := TIdSSLIOHandlerSocketOpenSSL.Create; HTTP := TIdHTTP.Create; HTTP.IOHandler := SSL; try try HTTP.Get(Url, RespData); HTTP.Request.Referer := Url; Result := RespData.DataString; except end; finally HTTP.Free; SSL.Free; FreeAndNil(RespData); end;end;function TForm1.PostMethod(Url: String; Data: UTF8String; Max: Integer): String;var PostData: TStringStream; RespData: TStringStream; HTTP : TIdHTTP; SSL : TIdSSLIOHandlerSocketOpenSSL;begin RespData := TStringStream.Create(''); PostData := TStringStream.Create(Data); SSL := TIdSSLIOHandlerSocketOpenSSL.Create; HTTP := TIdHTTP.Create; HTTP.IOHandler := SSL; try try if HTTP = nil then Exit; HTTP.Post(Url, PostData, RespData); Result := RespData.DataString; HTTP.Request.Referer := Url; except end; finally HTTP.Disconnect; HTTP.Free; SSL.Free; FreeAndNil(RespData); FreeAndNil(PostData); end;end;
(3)增加5个按钮,分别实行
获取Access_Token
procedure TForm1.Button_GetAccessTokenClick(Sender: TObject);begin //取得gsAccessToken wcGetAccessToken; // Memo1.Lines.Add(#13#10'gsAccessToken : '); Memo1.Lines.Add(gsAccessToken); //Memo1.Lines.Add(gsResp);end;
获取Jsapi_ticket
procedure TForm1.Button_GetJsapi_ticketClick(Sender: TObject);begin //取得Jsapi_ticket wcGetJsapi_ticket; // Memo1.Lines.Add(#13#10'gsJsapi_ticket : '); Memo1.Lines.Add(gsJsapi_ticket); //Memo1.Lines.Add(gsResp);end;
获取Signature
procedure TForm1.Button_GetSignatureClick(Sender: TObject);begin //显示 打算署名 Sigature 的原始字符串 Memo1.Lines.Add(#13#10'gsSigatureSource : '#13#10 +Format('jsapi_ticket=%s&noncestr=%s×tamp=%s&url=%s', [gsJsapi_ticket, gsNonceStr, gsTimeStamp, gsFull//'https://www.delphibbs.com/scan' ])); //取得Signature,即对原始字符串进行Sha1编码 gsSigature := wcGetSignature( gsJsapi_ticket, gsNonceStr, gsTimeStamp, gsFull//'https://www.delphibbs.com/scan' ); Memo1.Lines.Add(#13#10'gsSigature : '); Memo1.Lines.Add(gsSigature);end;
配置wx.Config
procedure TForm1.Button_wxConfigClick(Sender: TObject);var sJS : string;begin sJS := 'wx.config({' +'debug: true,' // 开启调试模式,调用的所有 api 的返回值会在客户端 alert 出来,若要查看传入的参数,可以在 pc 端打开,参数信息会通过 log 打出,仅在 pc 端时才会打印。 +'appId: '''+_Appid+''',' // 必填,"大众年夜众号的唯一标识 +'timestamp: '''+gsTimeStamp+''',' // 必填,天生署名的韶光戳 +'nonceStr: '''+gsNonceStr+''',' // 必填,天生署名的随机串 +'signature: '''+gsSigature+''',' // 必填,署名 +'jsApiList: [''scanQRCode'']' // 必填,须要利用的 JS 接口列表 +'});'#13 +'wx.ready(function () {' +'wx.scanQRCode({' +'needResult: 1,' // 默认为0,扫描结果由微信处理,1则直接返回扫描结果, +'scanType: ["qrCode","barCode"],' // 可以指定扫二维码还是一维码,默认二者都有 +'success: function (res) {' //+'alert(res);' +'var result = res.resultStr;' // 当needResult 为 1 时,扫码返回的结果 +'window.location.replace("'+gsUrl+'?"+result);' +'}' +',cancel: function (res){' //+'alert("CANCEL!");' +'window.location.replace("'+gsUrl+'");' +'}' +'});' +'});' +''; dwRunJS(sJS,self);end;
打开微信扫一扫
procedure TForm1.Button_QrcodeClick(Sender: TObject);var sJS : string;begin sJS := 'that = this;' +'wx.scanQRCode({' +'needResult: 1,' // 默认为0,扫描结果由微信处理,1则直接返回扫描结果, +'scanType: ["qrCode","barCode"],' // 可以指定扫二维码还是一维码,默认二者都有 +'success: function (res) {' //+'alert(res);' +'var result = res.resultStr;' // 当needResult 为 1 时,扫码返回的结果 +'that.button_qrcode__cap = result;' +'window.location.replace("'+gsUrl+'?"+result);' +'}' +',cancel: function (res){' //+'alert("CANCEL!");' +'window.location.replace("'+gsUrl+'");' +'}' +'});'; dwRunJS(sJS,self);end;
(3)在DeWeb的窗体启动事宜OnMouseDown中自动启动扫一扫
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);begin //:::OnMouseDown为deweb主窗体启动后自动实行的事宜 //<取得AccessToken //1 根据接口URL和 _AppID, _AppSecret 天生终极接口 URL //2 通过get取得返回值 //3 解析返回的JSON字符串,取得access_token值 Button_GetAccessTokenClick(Self); //> //<取得Jsapi_ticket //1 根据gsAccessToken得到URL //2 get取得结果 //3 解析JSON结果,得到 Jsapi_ticket Button_GetJsapi_ticketClick(Self); //> //<打算署名 //1 取得 打算署名 Sigature 的原始字符串 //2 取得Signature,即对原始字符串进行Sha1编码 Button_GetSignatureClick(Self); //> //<配置wx.config //1 实行wx.config //2 在上一步实行成功后,调用扫一扫 //3 在扫一扫成功后,转至带结果参数的指定回调地址 Button_wxConfigClick(Self); //>end;
四、常见问题
做完了觉得大略,实在还是有许多坑
紧张公众号设置
紧张包括:白名单设置、非80端口、JS接口安全域名等
紧张办理方法是wx.config中设置debug为true,
这样可以开启调试模式,可以动态显示缺点信息,逐一办理就好。
办法总比问题多!
有问题欢迎留言互换!
或Q 4530 0355