Project Address:vue-webview-js-bridge
Main functions: Based on webview javascript Bridge development of WebView-Js-bridge vue plug-in, more nonsense behind, you can directly see the project. If you happen to have nothing to do, just kill time
The story background
I front-end, in a mobile office APP team. RN and WEEX are not used because the service is simple. Simple use native to make a shell, the main logic is front-end control. The main technology stack is Vue.
The bug appears
Over a period of time, the team received multiple feedback that the APP needed to be re-logged in every day. As the front end of the team, I was very surprised, because the login large token is saved in the front end, valid for three days, how could it be possible to log in every day?
Trying to reason
- The token is valid for three days
- None of the team members had a problem with their phones, proving the logic
- After collecting the information of the mobile phones of the problem feeders, it was found that the phones of all the feeders had one thing in common: insufficient storage space (ios), and the problems were mainly concentrated on iphones
Locate the cause of the problem. It may be because the storage space of the mobile phone is insufficient and the stored tokens are cleared. Let’s start with that… Could it be that the phone ran out of memory space and cleaned up the stored token as useless information? (The token is stored in localStorage). According to Google, ios does have such a situation. When the phone’s storage space is insufficient, it will clean up the information deemed useless by the system and provide an environment for the main programs to run.
Problem of repetition
Find an Apple test machine that doesn’t have enough storage space, log in to the APP, and find a really big movie to download. At that point, the system clears up space for downloading movies. Turns out the APP needs to be logged in again. Problem recur, cause confirmed.
To solve the problem
A small APP that introduces a local database like SQLite just to store tokens is overkill. But localstorage, cookies and other places that can be stored are within the scope of system cleaning. Finally, we decided to store the token in native.
The solution
- Native develops functions similar to localStorage
- The token is stored in the native end
- When the front-end starts, it queries whether the Native terminal has any token and synchronizes the token to localStorage. If the front-end does not, the login page is redirected.
- Other logic unchanged
Program is determined, a word, roll up your sleeves a fierce dry…
Pit pit
Are you sick? , will not describe the past, love dearly. The front-end and Native communication uses WebViewJavascriptBridge, which is the problem here. See the code:
import jsBridge from './utils/native'
// omit n lines...
router.beforeEach((to, from, next) = > {
if (to.meta.auth) {
// The problem is that the jsBridge instance has not been initialized from the time APP starts to the time VUE runs here, so jsBridge is undiam
jsBridge.callHandler('getStorage', {key: 'token'}).then(res= > {
let token = res.body
if(token && token ! = ='null') {
next()
} else {
next('/login')
}
store.commit('UPDATE_TOKEN', {token})
})
} else {
next()
}
})
// omit n lines...
Copy the code
The problem has been identified because the jsBridge instance was not initialized when it was called. Interested can go to see the source code of WebViewJavascriptBridge, although the initialization time is very short, but it has caused problems, APP to start here error.
Continue to solve the problem: since the initialization is not complete, let’s wait until it is complete. Someone suggested using setTimeout, but how much? After all, different mobile phone initialization time is still different. Setting long affects the experience, as a front-end if the user experience does not care what front-end, so this easiest and lowest method was passed.
Think of an elegant solution
This is the original intention of this package I wrote, so much nonsense, to get to the point
- From a problem solving point of view
Since you haven’t initialized the jsBridge instance, we’ll wait until the instance is initialized and send it back, so we don’t have to worry about the bridge instance being unavailable
The core code
// ...
init (callback) {
if (window.WebViewJavascriptBridge) {
return callback(window.WebViewJavascriptBridge)
}
if (window.WVJBCallbacks) {
return window.WVJBCallbacks.push(callback)
}
window.WVJBCallbacks = [callback]
var WVJBIframe = document.createElement('iframe')
WVJBIframe.style.display = 'none'
WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__'
document.documentElement.appendChild(WVJBIframe)
setTimeout(function () {
document.documentElement.removeChild(WVJBIframe)
}, 0)
}
callHandler (payload) {
let _resolve
let _reject
const readyPromise = new Promise((resolve, reject) = > {
_resolve = resolve
_reject = reject
})
this.init(function (bridge) {
try {
bridge.callHandler(nativeHandlerName, payload, (response) => {
_resolve(response)
})
} catch (e) {
_reject(e)
}
})
return readyPromise
}
// ...
Copy the code
Accustomed to the use of Promise invocation, the call method Promise processing.
subsequent
In order to develop efficiency, we can’t debug in the APP all the time, so we added mock function and debug function.
Project address: VUe-webview-Js-bridge If you happen to have some help, welcome star, welcome PR
The first time to write a technical article, the first time to write package. It’s a little confusing. Comments and discussion are welcome. Together with progress