网页程序迁移至微信小程序web-view详解

2018/08/02 · JavaScript
· 小程序

原文出处: NeoPasser   

小程序现在越来越流行,但是公司的很多项目都是用网页写的,小程序语法不兼容原生网页,使得旧有项目迁移至小程序代价很高。

小程序之前开放了webview功能,可以说是网页应用的一大福音了,但是微信的webview有一些坑,这篇文章就是列举一下我在开发过程中遇到的一些问题以及我找到的一些解决方案。

直接放到需要显示授权页的onload里

onLoad: function (options) {

      //登录授权部分逻辑

      var that = this

      var title = arguments[2] ? arguments[2] :
‘授权登录失败,部分功能将不能使用,是否重新登录?’;//当用户取消授权登录时,弹出的确认框文案

      var user = wx.getStorageSync(‘user’);//登录过后,用户信息会缓存

      console.log(user)

      if (!user) {

        console.log(!user)

        // 弹出授权页

        wx.login({

          success: function (res) {

            console.log(‘弹出授权页成功’)

            var code = res.code;

            // 是否允许授权

            wx.getUserInfo({

              success: function (res) { //用户点击 “同意”

                console.log(‘允许授权:’)

                wx.setStorageSync(“user”, res)//本地缓存user数据 
下次打开不需要登录

                var app = getApp()

                app.globalData.user = res//在当前的app对象中缓存user数据

                // 同步信息到页面

                that.setData({

                  userInfo: app.globalData.user.userInfo

                })         

              },

              fail: function (res) { //用户点击 “拒绝”

                console.log(‘拒绝授权’)

                wx.showModal({  //自定义弹框显示是否重新同意授权

                  title: ‘提示’,

                  content: title,

                  showCancel: true,

                  cancelText: “否”,

                  confirmText: “是”,

                  success: function (res) { //调用模态弹窗成功

                    if (res.confirm) { //如果用户重新同意了授权登录

                      if (wx.openSetting) {  //当前微信的版本
,是否支持openSetting,调出小程序设置页面,开启授权

                        wx.openSetting({

                          success: (res) => {

                            if (res.authSetting[“scope.userInfo”]) {

                              console.log(‘用户重新同意授权’)

                              wx.getUserInfo({ 
//跟上面的wx.getUserInfo处理逻辑一样

                                success: function (res) {

                                    wx.setStorageSync(“user”, res)     
                     

                                    var app = getApp()

                                    app.globalData.user = res

                                    that.setData({

                                      userInfo:
app.globalData.user.userInfo

                                    })

                                }

                              })

                            } else {  //还是拒绝

                             
console.log(‘用户还是拒绝授权,登陆失败,此处应该变换页面’)

                            }

                          },

                          fail: function () { 
//调用失败,授权登录不成功

                            console.log(‘登陆失败’)

                          }

                        })

                      } else {

                       
console.log(‘当前用户微信版本不支持openSetting,登陆失败’)

                      }

                    }else{

                     
//可以在这里添加一个确认授权的页面,如果不想加的话,就需要每次跳转到这个页面都检测一遍是否授权,那么这个函数就应该放到其他钩子函数里了

                      console.log(‘用户第二次拒绝了授权,在此处变换页面’)

                    }

                  }

                })

              }

            })

          }

        })

      } else {//如果缓存中已经存在user  那就是已经登录过

        var app = getApp()

        app.globalData.user = user

      } 

  }

也可以把它封装成一个函数,用的时候调用就可以了

遇到的问题

  1. openid登录问题
  2. webview动态src
  3. 支付功能
  4. 分享功能
  5. 扫描普通二维码跳转特定页面
  6. 返回按钮缺失问题

openid登录问题

微信webview的使用方法很简单,只要如下设置src就可以展示具体的网站了。

<!– wxml –> <!– 指向微信公众平台首页的web-view –>
<web-view src=”https://mp.weixin.qq.com/"&gt;&lt;/web-view&gt;

1
2
3
<!– wxml –>
<!– 指向微信公众平台首页的web-view –>
<web-view src="https://mp.weixin.qq.com/"></web-view>

微信环境里的很多网页都是用页面要实现网站的登录功能,只要把登录的信息,比如openid或者其他信息拼接到src里就好了。

这里有个问题,公众号的账号体系一般是以openid来判断唯一性的,小程序是可以获取openid的,但是小程序的openid和原公众号之类的openid是不一样的,需要将原先的openid账号体系升级为unionid账号体系。

威尼斯人线上娱乐,以下是微信对unionid的介绍

获取用户基本信息(UnionID机制)

在关注者与公众号产生消息交互后,公众号可获得关注者的OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的。对于不同公众号,同一用户的openid不同)。公众号可通过本接口来根据OpenID获取用户基本信息,包括昵称、头像、性别、所在城市、语言和关注时间。

请注意,如果开发者有在多个公众号,或在公众号、移动应用之间统一用户帐号的需求,需要前往微信开放平台(open.weixin.qq.com)绑定公众号后,才可利用UnionID机制来满足上述需求。

UnionID机制说明:

开发者可通过OpenID来获取用户基本信息。特别需要注意的是,如果开发者拥有多个移动应用、网站应用和公众帐号,可通过获取用户基本信息中的unionid来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号,用户的unionid是唯一的。换句话说,同一用户,对同一个微信开放平台下的不同应用,unionid是相同的。

做完以上步骤,就可以调用小程序api wx.getUserInfo()
来获取用户信息了,此步骤需要进行后台信息解密过程,在此就不再赘述,结合小程序api文档操作就好。

获取到unioid之后,将unionid信息拼接到src就可以进行网页登录操作了(前提是网页可以用跳转链接的方式登录,类似公众号页面获取openid的形式)。

webview动态src

微信的webview有个坑的地方,不会动态的监听src的变化,这就造成了一个问题,要通过改变src实现页面跳转就不可以了。
我尝试了一些方法之后,找到了一个解决方案:

微信webview在页面load的时候会加载一次webview,我们就利用这个特性来实现动态src问题。

  1. 首先把要跳转的链接信息设置成全局变量,要改变src的时候,先把要src以’?‘拆分为链接和参数两部分,存入全局函数,再调用onLoad就可以实现webview刷新了。
  2. 页面跳转时,我们也需要src的动态刷新,所以要把链接信息存入全局函数;页面跳转时,onShow函数会被调用,这时候再调用一次onLoad就可以了。

data: { url: ”, loaded: false } // 小程序js里的onLoad函数可以写成这样
onLoad: function () { this.setData({ url: getApp().globalData.urlToken +
‘?’ + getApp().globalData.urlData }) }, changUrl: function () {
getApp().globalData.urlToken = ‘https://www.example.com
getApp().globalData.urlToken = ‘a=1&b=2’ //
直接调用onLoad,就会实现src的刷新 this.onLoad() }, onShow: function () {
if (!this.data.loaded) { // 第一次不运行 this.setData({ loaded: true })
return } // 直接调用onLoad,就会实现src的刷新 this.onLoad() } //
wxml可以写成这样 <web-view src=”{{url}}”></web-view>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
data: {
    url: ”,
    loaded: false
}
// 小程序js里的onLoad函数可以写成这样
onLoad: function () {
    this.setData({
      url: getApp().globalData.urlToken + ‘?’ +  getApp().globalData.urlData
    })
},
changUrl: function () {
    getApp().globalData.urlToken = ‘https://www.example.com’
    getApp().globalData.urlToken = ‘a=1&b=2’
    // 直接调用onLoad,就会实现src的刷新
    this.onLoad()
},
onShow: function () {
    if (!this.data.loaded) {
      // 第一次不运行
      this.setData({
        loaded: true
      })
      return
    }
    // 直接调用onLoad,就会实现src的刷新
    this.onLoad()
  }
 
// wxml可以写成这样
<web-view src="{{url}}"></web-view>

支付功能

webview里面可以通过jssdk来实现一些小程序功能,但不能直接调用小程序的支付功能,这时候我们就需要转变一下策略了:

  1. 在网页里引入微信jssdk
  2. 在网页需要发起支付的地方,调用跳转页面的接口,控制小程序跳转到小程序的支付页面(这个要在小程序里单独写的),跳转的时候,需要把订单的一些信息都拼接到链接里,订单信息由后台返回,需要通过微信支付系统的统一下单接口,具体参看支付文档。
  3. 跳转到小程序支付页面后,由小程序页面发起支付,支付完成后跳转回webview页面,通过之前设置的动态src,控制webview跳转到特定的页面。

JavaScript

// 网页引入jssdk // 网页发起支付 wx.miniProgram.navigateTo({ //
payData由后台返回,主要是需要统一下单平台的prepay_id url:
‘../pay/index?data=’ + encodeURIComponent(JSON.stringify(payData)) }) //
微信支付页面 onLoad: function (option) { let page = this try { let data
= JSON.parse(option.data) if (!data || !data.prepay_id) {
console.error(‘支付参数错误,请稍后重试’, data) } wx.requestPayment({
timeStamp: ” + data.timestamp, nonceStr: data.nonceStr, package:
‘prepay_id=’ + data.prepay_id, paySign: data.paySign, signType:
data.signType, success: function (res) { getApp().globalData.urlToken =
`paySuccess.html` // 支付成功 getApp().globalData.urlData =
‘data=paySuccessData’ wx.navigateTo({ url: ‘/page/home/index’, }) },
fail: function (res) { getApp().globalData.urlToken = `payError.html`
// 支付失败 getApp().globalData.urlData = ‘data=payErrorData’
wx.navigateTo({ url: ‘/page/home/index’, }) }, complete: function (res)
{ } }) } catch (e) { console.error(‘支付错误’, e) } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 网页引入jssdk
 
// 网页发起支付
wx.miniProgram.navigateTo({
    // payData由后台返回,主要是需要统一下单平台的prepay_id
    url: ‘../pay/index?data=’ + encodeURIComponent(JSON.stringify(payData))
})
// 微信支付页面
onLoad: function (option) {
    let page = this
    try {
      let data = JSON.parse(option.data)
      if (!data || !data.prepay_id) {
        console.error(‘支付参数错误,请稍后重试’, data)
      }
      wx.requestPayment({
        timeStamp: ” + data.timestamp,
        nonceStr: data.nonceStr,
        package: ‘prepay_id=’ + data.prepay_id,
        paySign: data.paySign,
        signType: data.signType,
        success: function (res) {
          getApp().globalData.urlToken = `paySuccess.html`
          // 支付成功
          getApp().globalData.urlData = ‘data=paySuccessData’
          wx.navigateTo({
            url: ‘/page/home/index’,
          })
        },
        fail: function (res) {
          getApp().globalData.urlToken = `payError.html`
          // 支付失败
          getApp().globalData.urlData = ‘data=payErrorData’
          wx.navigateTo({
            url: ‘/page/home/index’,
          })
        },
        complete: function (res) {
        }
      })
    } catch (e) {
      console.error(‘支付错误’, e)
    }
  }