123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323 |
- import cookies from 'js-cookie'
- import semver from 'semver'
- import { COOKIE_ROOT_DOMAIN, COOKIE_APP_KEY, COOKIE_APP_EXTRA_KEY, COOKIE_ACCESS_TOKEN_KEY, MSG_REQUIRE_LOGIN, APP_INJECT_COOKIE_KEYS, DEF_SYNCED_COOKIE_EXP } from './constant'
- import { Notifier, SyncCookiesOptions } from '../types/global'
- const setupWebViewJavascriptBridge = (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 = 'https://__bridge_loaded__'
- document.documentElement.appendChild(WVJBIframe)
- setTimeout(function () {
- document.documentElement.removeChild(WVJBIframe)
- }, 0)
- }
- const parseJWT = (token: string): any => {
- const payloadStr = token.split('.')[1]
- if (!payloadStr) {
- return null
- }
- try {
- return JSON.parse(atob(payloadStr))
- } catch (e) {
- // tslint:disable-next-line
- console.error('[parseJWT]', e)
- }
- return null
- }
- const getAppInfo = () => {
- const val = cookies.get(COOKIE_APP_KEY)
- const matched = val && /^(ios|android)\ ((?:\d\.?)+)$/.exec(val)
- if (!matched) {
- return null
- }
- return {
- os: matched[1],
- version: matched[2]
- }
- }
- const getAppExtra = (): any => {
- const val = cookies.get(COOKIE_APP_EXTRA_KEY)
- const segments = val && val.split(/\s+/)
- if (!segments || !segments.length) {
- return {}
- }
- return segments.reduce((map, item) => {
- const matched = /^([0-9a-zA-Z_-]+)\/(.+)$/.exec(item)
- if (matched) {
- map[matched[1]] = matched[2]
- }
- return map
- }, {})
- }
- let cachedAppInfo: any
- let cachedappExtra: any
- class ProginnBridge {
- root = window.app_event || window.appBridge
- private notifier?: Notifier
- constructor(opts?: {
- notifier?: Notifier
- }) {
- const { notifier } = opts || {}
- this.notifier = notifier
- }
- get appInfo() {
- cachedAppInfo = cachedAppInfo || getAppInfo()
- return cachedAppInfo
- }
- get appExtra() {
- cachedappExtra = cachedappExtra || getAppExtra()
- return cachedappExtra
- }
- get appVersion() {
- return this.appInfo?.version
- }
- get os() {
- return this.appInfo?.os
- }
- get isInApp() {
- return !!(this.appInfo || this.root)
- }
- get isAndroid() {
- return /Android/.test(window.navigator.userAgent) || this.os === 'android' || false
- }
- get isIos() {
- return /iP(hone|ad|od)/.test(window.navigator.userAgent) || this.os === 'ios' || false
- }
- get cookie() {
- return cookies.get()
- }
- get isLogined() {
- return !!cookies.get(COOKIE_ACCESS_TOKEN_KEY)
- }
- get uid(): string | null {
- const token = cookies.get(COOKIE_ACCESS_TOKEN_KEY)
- const payload = token && parseJWT(token)
- return payload?.uid
- }
- inject(name: string, cb: (...args: any) => void, root = 'Proginn') {
- window[root] = window[root] || {}
- window[root][name] = cb
- }
- invoke(fn: string, data: any = null, cb: Function = () => {}) {
- if (this.isIos && this.compareAppVersion('gte', '4.22.0')) {
- setupWebViewJavascriptBridge((bridge) => {
- bridge.callHandler(fn, data, cb)
- })
- return
- }
- if (!this.root) {
- // tslint:disable-next-line
- console.warn(`Bridge invoke ${fn} skipped.`)
- return null
- }
- if (this.isAndroid) {
- if (typeof this.root[fn] === 'function') {
- return data ? this.root[fn](data) : this.root[fn]()
- } else {
- return null
- }
- } else {
- return this.root(fn, data)
- }
- }
- back() {
- if (!this.isInApp) {
- window.history.back()
- } else {
- if (this.isIos && this.compareAppVersion('gte', '4.22.0')) {
- this.invoke('back')
- }
- else {
- this.invoke('back_page')
- }
- }
- }
- close() {
- if (this.isAndroid || this.compareAppVersion('lt', '4.22.0')) {
- this.invoke('finishActivity')
- } else {
- this.invoke('close')
- }
- }
- load(url: string) {
- window.location.href = url
- }
- open(url: string, title?: string) {
- if (this.isInApp && (!this.isAndroid || this.compareAppVersion('gte', '4.20.0'))) {
- url = `proginn://webview?url=${encodeURIComponent(url)}${title ? '&title=' + encodeURIComponent(title) : ''}`
- }
- this.load(url)
- }
- login() {
- if (!this.isInApp) {
- return
- }
- this.load('proginn://login?backToPage=true')
- }
- checkLogin(force = false) {
- if (force || !this.isLogined) {
- this.notifier && this.notifier(MSG_REQUIRE_LOGIN, -99)
- this.login()
- return false
- }
- return true
- }
- compareAppVersion(operator: 'gt' | 'lt' | 'gte' | 'lte' | 'eq' | 'neq', version: string) {
- return this.appVersion ? semver[operator](this.appVersion, version) : false
- }
- syncCookies(opts?: SyncCookiesOptions) {
- opts = opts || {}
- opts.domain = opts.domain || COOKIE_ROOT_DOMAIN
- opts.expires = opts.expires || DEF_SYNCED_COOKIE_EXP
- for (const key of APP_INJECT_COOKIE_KEYS) {
- const val = cookies.get(key)
- if (val) {
- cookies.set(key, val, opts)
- }
- }
- }
- // generally to fix android webview cookies non-inject bug
- cacheCookiesInStorage() {
- for (const key of APP_INJECT_COOKIE_KEYS) {
- const val = cookies.get(key)
- if (val) {
- window.localStorage.setItem(key, val)
- } else {
- window.localStorage.removeItem(key)
- }
- }
- }
- loadCookiesInStorage(opts?: SyncCookiesOptions) {
- opts = opts || {}
- opts.domain = opts.domain || COOKIE_ROOT_DOMAIN
- opts.expires = opts.expires || DEF_SYNCED_COOKIE_EXP
- for (const key of APP_INJECT_COOKIE_KEYS) {
- // pass if already exists
- if (cookies.get(key)) {
- continue
- }
- const val = window.localStorage.getItem(key)
- if (val) {
- cookies.set(key, val, opts)
- }
- }
- }
- // load data
- loadUserData(data: any) {
- if (this.isAndroid) {
- this.invoke('user_load', data)
- }
- else if (this.compareAppVersion('lt', '4.22.0')) {
- this.invoke('user_load', {
- userInfo: data,
- })
- }
- else {
- this.invoke('loadUserData', data)
- }
- }
- loadShareData(data: any) {
- if (this.isAndroid) {
- this.invoke('load_share_data', JSON.stringify(data))
- }
- else if (this.compareAppVersion('lt', '4.22.0')) {
- this.invoke('load_share_data', data)
- }
- else {
- this.invoke('loadShareData', data)
- }
- }
- loadTopicData(data: {
- topic_id: string
- user_id: string
- share_content: any
- topics: any[]
- }) {
- if (this.isAndroid) {
- this.invoke('topic_load', data.topic_id)
- }
- else if (this.compareAppVersion('lt', '4.22.0')) {
- this.invoke('topic_load', data)
- }
- else {
- this.invoke('loadTopicData', data)
- }
- }
- // ui
- setNavigationBarColor(hex: string) {
- if (this.isAndroid || this.compareAppVersion('lt', '4.22.0')) {
- this.invoke('setTitleBarColor', hex)
- } else {
- this.invoke('setNavigationBarColor', hex)
- }
- }
- setNavigationBarTitle(text: string) {
- this.invoke('setNavigationBarTitle', text)
- }
- }
- export default ProginnBridge
|