Preface,

The company’s H5 project needs IM access, other platforms have already connected with IM services provided by Udesk, and H5 also needs to be consistent. Before the development, I heard from android and iOS colleagues that Udesk has many holes, and they have changed several versions of the source code. I wonder if H5 will be so exciting. Holding uneasy mood ready to try.

This paper recorded a pit stepping process when Vue version H5 was connected to Udesk WebIM web plug-in. On the one hand, it was to record myself, and on the other hand, it was to help children who were about to pit stepping to avoid pit stepping.

First, register Udesk

If you do not have an account, you need to register.

Udesk website: www.udesk.cn

After registration, you can obtain the trial account from the customer service for free, and you need to pay for the permission to use the IM plug-in function for your own or company account.

Second, use IM plug-in

The following lists the main processes. For details, refer to udESk text IM interconnection documents: www.udesk.cn/doc/thirdpa…

1. PerformUdeskProvided functions

Udesk provides a function to create a script to load a remote resource:

(function (a, h, c, b, f, g) {
      a.UdeskApiObject = f
      a[f] =
        a[f] ||
        function () {
          (a[f].d = a[f].d || []).push(arguments)
        }
      g = h.createElement(c)
      g.async = 1
      g.src = b
      c = h.getElementsByTagName(c)[0]
      c.parentNode.insertBefore(g, c)
    })(
      window.document.'script'.'https://assets-cli.udesk.cn/im_client/js/udeskApi.js'.'ud'
    )
Copy the code

Access to Baidu statistics of children’s shoes will certainly feel deja vu. It creates a script tag for loading Udesk WebIM web plugins and inserts it into the head. Due to the async property added to the script tag, it will be executed immediately after loading the JS resource. After execution, an UD object is mounted on the window, and parameters are passed to the UD during initialization.

2. Initialize the UD

ud({
  "code": "xxxx"."link": "https://xxx.xxxx.cn/im_client/?web_plugin_id=1"."isInvite": true."mode": "inner"."color": "#307AE8"."pos_flag": "srb"."language": "en-us"."onlineText": "Contact customer service and consult online."."offlineText": "Customer service is closed. Please leave a message."."mobile": { // Provide PC and mobile customization for responsive layout
    "mode": "blank"."color": "#307AE8"."pos_flag": "crb"."onlineText": "Contact customer service and consult online."."offlineText": "Customer service is closed. Please leave a message."}})Copy the code

These are common parameters that can be transmitted during initialization. Code and link are mandatory, and other parameters can be selected as required.

In VUE we can write a UDSK utility function

// udesk.js
export default {
  init () {
    if (!window.ud) {
      this.createUdeskScript()
    }
  },
  createUdeskScript () {
    (function (a, h, c, b, f, g) {
      a.UdeskApiObject = f
      a[f] =
        a[f] ||
        function () {
          (a[f].d = a[f].d || []).push(arguments)
        }
      g = h.createElement(c)
      g.async = 1
      g.src = b
      g.id = useUdeskScriptId
      c = h.getElementsByTagName(c)[0]
      c.parentNode.insertBefore(g, c)
    })(
      window.document.'script'.'https://assets-cli.udesk.cn/im_client/js/udeskApi.js'.'ud'
    )
    const ud = window.ud
    const udParams = {
      code,
      link,
      ... // Other parameters
      }
    }
    ud(udParams)
  }
}
Copy the code

Just use it in main.js

// main.js
import Udesk from './utils/udesk'
Udesk.init()
Copy the code

Udesk global object

After initialization, udesk will be mounted on the window, and it will print something like this:

Check the DOM node and you’ll seeudeskExample Create a file whose ID isudesk_containerdiv, the structure is as follows.

The div containers with ids udesk_bTN and UDesk_panel are the buttons that open the IM session panel (you can customize location, image style, etc.) and IM session panel, respectively.

The IM session panel is displayed by embedding iframe. The session panel is shown below:

At this point, the most basic IM functionality is basically available. But, if we want to fill in the details, we still need to do a lot more.

Customization of Udsk information button

Why custom?

1. In this project, the requirement is that there will be another button suspended in the lower right corner below the information button, with the same style as follows:

The official background of Udesk provides the configuration of IM message button positioning, which can be adjusted in the background by itself, but unfortunately, the style of unread red dots cannot be adjusted, and the positioning will lead to alignment errors with another icon.

2. Unread display different page styles, such as:

3. After Udesk initialization, the style of the same page is fixed, while the style of single-page application (Vue,React) is different from page to page. Therefore, Udesk configuration for automatic production of information buttons does not meet our requirements.

To sum up the above three points determine the style of the button that writes unread information and handles unread information according to the provided interface callback.

4. Synchronize the number of unread messages

Since multiple pages have unread entries, we need to synchronize the information to each page when we receive it. Vuex is a good choice for managing the number of unread entries.

Ud initialization gives an onUnread callback that handles unread numbers. Considering that H5 project users have a high chance of receiving unread messages and cutting them out, it is important to cache unread messages.

onUnread: function (data) { const count = data.count Store.commit('SET_UNREADCOUNT', SetLocal (count) _this.setLocal(count)Copy the code

Also, unread is pulled from the cache after initialization

// onReady onReady in udParams: Function () {const onUnreadCount = _this.getLocal() if (onUnreadCount &&onunreadCount * 1 > 0) {function() {const onUnreadCount = _this.getLocal() if (onUnreadCount &&onunreadCount * 1 > 0) { Store.commit('SET_UNREADCOUNT', onUnreadCount) } }, getLocal () { return localStorage.getItem('onUnread') }Copy the code

This way, if you need to use unread components or pages, you can pull it out of the Store and use it easily.

Five, encountered pit

1. Open the session panel in Vue project and click the browser back button. Normally, we expect to close the session panel and return to the previous page, but this is not the case in Vue.

Cause: The Vue is a single-page application. The browser’s rollback forward controls the routing of the Vue, and the entire page is not updated. In addition, the session panel is open.

How do you solve it? Udesk provides two methods: hidePanel and showPanel. HidePanel and open session panel respectively.

Use ud(“hidePanel”), UD (“showPanel”), ud.showPanel() and ud.hidePanel(). By combining these two methods, we can solve the above problem.

Fuck!!

Add a new page for storing routes, let’s say this page is called UdeskPanel.

This page does not write any style, it is only used to handle the Udsk session panel logic. The route hits the page and calls the showPanel method. The route leaves the page and calls the hidePanel method.

In order to unify the methods of Udesk, we integrate the methods of displaying hidden session panels into udesk.js:

// udesk.js
export default {
  init () {
    if (!window.ud) {
      this.createUdeskScript()
    }
  },
  openUdPanel () {
    if (window.ud) {
      this.show()
      const ud = window.ud
      ud('showPanel')
    }
  },
  hideUdPanel () {
    if (window.ud) {
      const ud = window.ud
      ud('hidePanel')
    }
  },
  createUdeskScript () {
    (function (a, h, c, b, f, g) {
      a.UdeskApiObject = f
      a[f] =
        a[f] ||
        function () {
          (a[f].d = a[f].d || []).push(arguments)
        }
      g = h.createElement(c)
      g.async = 1
      g.src = b
      g.id = useUdeskScriptId
      c = h.getElementsByTagName(c)[0]
      c.parentNode.insertBefore(g, c)
    })(
      window.document.'script'.'https://assets-cli.udesk.cn/im_client/js/udeskApi.js'.'ud'
    )
    const ud = window.ud
    const udParams = {
      code,
      link,
      ... // Other parameters
      }
    }
    ud(udParams)
  }
}
Copy the code

UdeskPanel page code:

// UdeskPanel.vue

<template>
  <section class="UdeskPanel"></section>
</template>

<script>
import Udesk from '.. /utils/udesk'
export default {
  name: 'UdeskPanel',
  data () {
    return {}
  },
  mounted () {
    Udesk.openUdPanel()
  },
  beforeRouteLeave (to, from, next) {
    Udesk.hideUdPanel()
    next()
  },
  methods: {}}</script>

Copy the code

The above problem is resolved and a new problem occurs. The user clicks to minimize the Udesk session panel to close the session panel and we are left with a blank page of the UdeskPanel.

That’s not what we want.

So we should also capture the event that closes the session panel. After checking the documentation, UD provides a callback method to onToggle. Checks whether the current session panel is open, if visible is true.

onToggle: function(data) { if (! Data.visible) {// Dialog window closes} else {// dialog window opens}}Copy the code

Using this method, we can globally maintain a variable for whether the session panel is open or not with Vuex. The UdeskPanel page listens for this variable, and when it is false to operate the route rollback, the previous code looks like this:

// UdeskPanel.vue

<template>
  <section class="UdeskPanel"></section>
</template>

<script>
import Udesk from '.. /utils/udesk'
import { mapGetters } from 'vuex'

export default {
  name: 'UdeskPanel',
  data () {
    return {}
  },
  mounted () {
    Udesk.openUdPanel()
  },
  computed: {
    ...mapGetters(['udTraceIsUP']),
    showPanel () {
      return this.$store.state.udesk.showPanel
    }
  },
  watch: {
    showPanel (newVal, oldVal) {
      if (newVal === false) {
      	this.$router.go(-1)
      }
    }
  },
  beforeRouteLeave (to, from, next) {
    Udesk.hideUdPanel()
    next()
  },
  methods: {}}</script>

Copy the code

Seems to have solved the problem.

However, if the user opens the page directly from the Session panel, click Minimize and the page will still be present.

This.$router.go(-1) does not meet our requirements if there is no previous routing record on the page. Therefore, we need to do something else to leave the page. Optimize the code again:

showPanel(newVal, oldVal) {
  if (newVal === false) {
    if (window.history.length <= 2) {
      this.$router.push('/') return false
    } else {
      this.$router.go( - 1)}}}Copy the code

This is compatible with the scenario of opening the session panel page directly.

Of course, you can also judge when directly opened to redirect to other pages, you can adjust according to demand.

2. Refreshing the page of a user session creates a new session, which is mistaken for a new user

The problem was discovered after the launch. (Fortunately, it was discovered quickly 🐶)

At that time after the discovery immediately rolled back, otherwise customer service MM’s heart must collapse, there will be overwhelming sessions into the customer service system background.

The reason why it was discovered after the launch was that the specified customer service test was set during the development process. When the same customer service access session was refreshed, no new session would be generated. However, a new session will be triggered when you remove the specified customer service, refresh it, or enter it from another portal.

That’s not what we want!

To solve this problem, I went to the documentation and found the session_key field. Session_key = session_key = session_key = session_key = session_key = session_key; 😁

but !

Repeat session problems still occur…

After harassing Udesk after-sales customer service constantly harassing questions and answers, the solution is fruitless…

In the end, I found their technical advice is to identify the user rather than the session, our scenario needs to distinguish the user rather than the session 😨!

Looking at the document again, I was ecstatic that 😁, the session_key mentioned earlier, needed to be replaced with web_token.

Ok, find the direction and try to modify step by step, see if it works.

Looking at the documentation and their examples, web_token is mounted under the Customer attribute of udParams (the initialization of the passed parameter object).

The customer object looks like this:

/ / SHA1 example
ud({
  "customer": {
    "nonce": "9ca6fff5a509fb887ac72cf5c92010e7"."signature": "9B2619225AA6476DC1EB80DBB8801E1575EBE39C"."timestamp": "1455675719000"."web_token": "[email protected]"}})Copy the code

Signature requires an encryption algorithm.

Encryption algorithm I choose his default SHA1, find a more downloaded wheel JS-SHA1

NPM is installed to generate signature method:

import sha1 from 'js-sha1'
/ / signature encryption algorithm (three steps) http://www.udesk.cn/doc/thirdparty/webim/#-_4
getSignature (nonce, timestamp, webToken) {
  let signStr = `nonce=${nonce}&timestamp=${timestamp}&web_token=${webToken}&${key}`
  signStr = sha1(signStr)
  signStr = signStr.toUpperCase()
  return signStr
}
Copy the code

Since H5 project has no user system, there is no identification such as user ID, so we use random number + timestamp to generate webToken

GetWebToken (timestamp) {// Customer unique identifier, The email address and mobile phone number are recommended. Only letters, digits, and underscores (_) are supported. Special characters are disabled. Let webToken const localSessionkey = localstorage. getItem('UDWebToken') if (! isEmpty(localSessionkey)) { webToken = localSessionkey } else { webToken = makeRandomStr(6) + timestamp localStorage.setItem('UDWebToken', webToken) } return webToken },Copy the code

When initializing, we change the corresponding:

// udesk.js
export default {
  init () {
    if (!window.ud) {
      this.createUdeskScript()
    }
  },
  openUdPanel () {
    if (window.ud) {
      this.show()
      const ud = window.ud
      ud('showPanel')
    }
  },
  hideUdPanel () {
    if (window.ud) {
      const ud = window.ud
      ud('hidePanel')
    }
  },
  createUdeskScript () {
    (function (a, h, c, b, f, g) {
      a.UdeskApiObject = f
      a[f] =
        a[f] ||
        function () {
          (a[f].d = a[f].d || []).push(arguments)
        }
      g = h.createElement(c)
      g.async = 1
      g.src = b
      g.id = useUdeskScriptId
      c = h.getElementsByTagName(c)[0]
      c.parentNode.insertBefore(g, c)
    })(
      window.document.'script'.'https://assets-cli.udesk.cn/im_client/js/udeskApi.js'.'ud'
    )
    const ud = window.ud
    const Timestamp = new Date().getTime()
    const Nonce = makeRandomStr(32)
    const Webtoken = this.getWebToken(Timestamp)
    const udParams = {
      code,
      link,
      customer: {
        nonce: Nonce,
        timestamp: Timestamp,
        web_token: Webtoken,
        signature: this.getSignature(Nonce, Timestamp, Webtoken)
      },
      ... // Other parameters
      }
    }
    ud(udParams)
  }
}
Copy the code

After the test, no matter how much refresh and switch, no new session will be triggered. Customer service MM also do not have to worry about the same user browsing H5 page opened a bunch of sessions. 👏 👏 👏

3. The commodity consulting object uploads javascript access mode and uploads parameters incorrectly

The so-called product consulting object is that the user clicks into the IM session panel from the product details to establish a session, and the customer service can see the product content that the user is browsing from the background. Udsk provided a method for our last consultation object.

However, when the parameters are dynamically passed in through javascript access, Udesk background cannot capture commodity information at all, only when it is written to a string. The specific reason is unknown.

Try to pass the parameter in URL mode

upLoadTrace (data) {
  const iframe = document.getElementById('udesk_iframe')
  const iframeSrc = iframe.src
  const { title, url, imageurl, city, address } = data
  const newSrc = iframeSrc +
  `&product_title=The ${encodeURIComponent(title)}` +
  `&product_url=The ${encodeURIComponent(url)}` +
  `&product_image=The ${encodeURIComponent(imageurl)}` +
  ` &The ${encodeURIComponent('product_ city')}=The ${encodeURIComponent(city)}` +
  (isEmpty(address) ? ' ' : ` &The ${encodeURIComponent('product_ address')}=The ${encodeURIComponent(address)}`)
  iframe.src = newSrc
}
Copy the code

4. After the IFrame SRC is changed, the rollback needs to be repeated

The commodity object consulted is successfully seen in the background by passing the parameter in URL mode. However, there is a new problem. When returning to the UdeskPanel page through the browser, there will be a jump exception. The interface returned is not our previous page. Finally learned:

When changeiframethesrcProperty, router.go(-1), does not implement the route backward, but instead treats the iframe as a window document, called the window documentwindow.history.go(-1)Does not change the route back function of the parent project. We need to use iframewindow.location.replaceWays to changeiframeContent to be accessed.

So iframe.src = newSrc above

Need to change to: the iframe contentWindow. Location. The replace (newSrc)

In this way the problem was solved.

5.Udesk does not provide a callback after the user sends the message

The project needs to count the number of sessions sent by users and make in-depth optimization for promotion, but Udesk does not provide this interface. After several attempts, it is found that the callback processing provided by Udesk needs to cooperate with JS in IFrame for postMessage interaction, and it is not possible to simply modify the initialized JS. Statistical requirements cannot be fulfilled. The good thing is that Udesk has received a work order. They say they are planning this feature and hope to launch it soon.

Six, summarized

Sure enough, Udesk has a lot going for it. On the one hand: Udesk’s documentation is really poor and inconvenient to read. On the other hand, Udesk provides so few interfaces that customization can be problematic. Of course, if you just use the basic functionality provided by Udesk without additional modifications, you can do just fine.

End of article. Thanks for reading, I hope you can help.

“Tips: Please note the original link: juejin.cn/post/685810…”