Bläddra i källkod

bump version to 0.3.0

Acathur 4 år sedan
förälder
incheckning
02ea4eca47

+ 3 - 0
dist/bridge/constant.d.ts

@@ -1,4 +1,7 @@
 export declare const COOKIE_ROOT_DOMAIN = "proginn.com";
 export declare const COOKIE_APP_KEY = "x_app";
+export declare const COOKIE_APP_EXTRA_KEY = "x_app_extra";
 export declare const COOKIE_ACCESS_TOKEN_KEY = "x_access_token";
 export declare const MSG_REQUIRE_LOGIN = "\u8BF7\u5728\u767B\u5F55\u540E\u64CD\u4F5C";
+export declare const APP_INJECT_COOKIE_KEYS: string[];
+export declare const DEF_SYNCED_COOKIE_EXP = 0.025;

+ 7 - 0
dist/bridge/constant.js

@@ -1,4 +1,11 @@
 export const COOKIE_ROOT_DOMAIN = 'proginn.com';
 export const COOKIE_APP_KEY = 'x_app';
+export const COOKIE_APP_EXTRA_KEY = 'x_app_extra';
 export const COOKIE_ACCESS_TOKEN_KEY = 'x_access_token';
 export const MSG_REQUIRE_LOGIN = '请在登录后操作';
+export const APP_INJECT_COOKIE_KEYS = [
+    COOKIE_APP_KEY,
+    COOKIE_APP_EXTRA_KEY,
+    COOKIE_ACCESS_TOKEN_KEY
+];
+export const DEF_SYNCED_COOKIE_EXP = 0.025; // d

+ 13 - 4
dist/bridge/index.d.ts

@@ -1,24 +1,33 @@
-import { Notifier } from '../types/global';
+import { Notifier, SyncCookiesOptions } from '../types/global';
 declare class ProginnBridge {
     root: any;
-    isAndroid: boolean;
     private notifier?;
     constructor(opts?: {
         notifier?: Notifier;
     });
+    get appInfo(): any;
+    get appExtra(): any;
+    get appVersion(): any;
+    get os(): any;
+    get isInApp(): boolean;
+    get isAndroid(): boolean;
+    get isIos(): boolean;
     get cookie(): {
         [key: string]: string;
     };
-    get isInApp(): boolean;
     get isLogined(): boolean;
     get uid(): string | null;
     inject(name: string, cb: (...args: any) => void, root?: string): void;
-    syncCookies(): void;
     invoke(fn: string, payload?: any): any;
     back(): void;
     load(url: string): void;
+    open(url: string, title?: string): void;
     login(): void;
     checkLogin(force?: boolean): boolean;
+    compareAppVersion(operator: 'gt' | 'lt' | 'gte' | 'lte' | 'eq' | 'neq', version: string): any;
+    syncCookies(opts?: SyncCookiesOptions): void;
+    cacheCookiesInStorage(): void;
+    loadCookiesInStorage(opts?: SyncCookiesOptions): void;
     userLoad(userInfo: any): void;
     topicLoad(id: string, data: {
         topic_id: string;

+ 106 - 23
dist/bridge/index.js

@@ -1,5 +1,6 @@
 import cookies from 'js-cookie';
-import { COOKIE_ROOT_DOMAIN, COOKIE_APP_KEY, COOKIE_ACCESS_TOKEN_KEY, MSG_REQUIRE_LOGIN } from './constant';
+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';
 const parseJWT = (token) => {
     const payloadStr = token.split('.')[1];
     if (!payloadStr) {
@@ -14,20 +15,67 @@ const parseJWT = (token) => {
     }
     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 = () => {
+    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;
+let cachedappExtra;
 class ProginnBridge {
     constructor(opts) {
         // @ts-ignore
-        this.root = window.app_event;
-        this.isAndroid = /Android/.test(window.navigator.userAgent);
+        this.root = window.app_event || window.appBridge;
         const { notifier } = opts || {};
         this.notifier = notifier;
     }
-    get cookie() {
-        return cookies.get();
+    get appInfo() {
+        cachedAppInfo = cachedAppInfo || getAppInfo();
+        return cachedAppInfo;
+    }
+    get appExtra() {
+        cachedappExtra = cachedappExtra || getAppExtra();
+        return cachedappExtra;
+    }
+    get appVersion() {
+        var _a;
+        return (_a = this.appInfo) === null || _a === void 0 ? void 0 : _a.version;
+    }
+    get os() {
+        var _a;
+        return (_a = this.appInfo) === null || _a === void 0 ? void 0 : _a.os;
     }
     get isInApp() {
-        // @ts-ignore
-        return !!(cookies.get(COOKIE_APP_KEY) || this.root || window.appBridge);
+        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);
@@ -41,28 +89,19 @@ class ProginnBridge {
         window[root] = window[root] || {};
         window[root][name] = cb;
     }
-    syncCookies() {
-        const app = cookies.get(COOKIE_APP_KEY);
-        const token = cookies.get(COOKIE_ACCESS_TOKEN_KEY);
-        const opts = {
-            domain: COOKIE_ROOT_DOMAIN,
-            expires: 7200
-        };
-        if (app) {
-            cookies.set(COOKIE_APP_KEY, app, opts);
-        }
-        if (token) {
-            cookies.set(COOKIE_ACCESS_TOKEN_KEY, token, opts);
-        }
-    }
     invoke(fn, payload) {
         if (!this.root) {
             // tslint:disable-next-line
             console.warn(`Bridge invoke ${fn} skipped.`);
-            return;
+            return null;
         }
         if (this.isAndroid) {
-            return this.root[fn] && this.root[fn](payload);
+            if (typeof this.root[fn] === 'function') {
+                return payload ? this.root[fn](payload) : this.root[fn]();
+            }
+            else {
+                return null;
+            }
         }
         else {
             return this.root(fn, payload);
@@ -79,6 +118,12 @@ class ProginnBridge {
     load(url) {
         window.location.href = url;
     }
+    open(url, title) {
+        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;
@@ -93,6 +138,44 @@ class ProginnBridge {
         }
         return true;
     }
+    compareAppVersion(operator, version) {
+        return this.appVersion ? semver[operator](this.appVersion, version) : false;
+    }
+    syncCookies(opts) {
+        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);
+            }
+        }
+    }
+    loadCookiesInStorage(opts) {
+        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);
+            }
+        }
+    }
     userLoad(userInfo) {
         this.invoke('user_load', this.isAndroid ? userInfo : {
             userInfo

+ 1 - 1
dist/request/index.d.ts

@@ -3,7 +3,7 @@ import ProginnBridge from '../bridge';
 import { Notifier } from '../types/global';
 declare const ProginnRequest: {
     create: (opts: {
-        baseURL: string;
+        baseURL?: string;
         bridge?: ProginnBridge;
         notifier?: Notifier;
     }) => (opts: {

+ 4 - 0
dist/types/global.d.ts

@@ -1 +1,5 @@
 export declare type Notifier = (msg: string, status?: string | number, resOrErr?: any) => void;
+export declare type SyncCookiesOptions = {
+    domain?: string;
+    expires?: number;
+};

+ 3 - 2
package.json

@@ -1,6 +1,6 @@
 {
   "name": "proginn-lib",
-  "version": "0.2.2",
+  "version": "0.3.0",
   "description": "Proginn front-end common library.",
   "main": "dist/index.js",
   "module": "dist/index.js",
@@ -15,7 +15,8 @@
   "dependencies": {
     "axios": "^0.19.2",
     "js-cookie": "^2.2.1",
-    "querystring": "^0.2.0"
+    "querystring": "^0.2.0",
+    "semver": "^7.3.2"
   },
   "devDependencies": {
     "@types/js-cookie": "^2.2.6",

+ 7 - 0
src/bridge/constant.ts

@@ -1,4 +1,11 @@
 export const COOKIE_ROOT_DOMAIN = 'proginn.com'
 export const COOKIE_APP_KEY = 'x_app'
+export const COOKIE_APP_EXTRA_KEY = 'x_app_extra'
 export const COOKIE_ACCESS_TOKEN_KEY = 'x_access_token'
 export const MSG_REQUIRE_LOGIN = '请在登录后操作'
+export const APP_INJECT_COOKIE_KEYS = [
+  COOKIE_APP_KEY,
+  COOKIE_APP_EXTRA_KEY,
+  COOKIE_ACCESS_TOKEN_KEY
+]
+export const DEF_SYNCED_COOKIE_EXP = 0.025 // d

+ 131 - 27
src/bridge/index.ts

@@ -1,6 +1,7 @@
 import cookies from 'js-cookie'
-import { COOKIE_ROOT_DOMAIN, COOKIE_APP_KEY, COOKIE_ACCESS_TOKEN_KEY, MSG_REQUIRE_LOGIN } from './constant'
-import { Notifier } from '../types/global'
+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 parseJWT = (token: string): any => {
   const payloadStr = token.split('.')[1]
@@ -19,10 +20,45 @@ const parseJWT = (token: string): any => {
   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 {
   // @ts-ignore
-  root = window.app_event
-  isAndroid = /Android/.test(window.navigator.userAgent)
+  root = window.app_event || window.appBridge
 
   private notifier?: Notifier
 
@@ -34,13 +70,38 @@ class ProginnBridge {
     this.notifier = notifier
   }
 
-  get cookie() {
-    return cookies.get()
+  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() {
-    // @ts-ignore
-    return !!(cookies.get(COOKIE_APP_KEY) || this.root || window.appBridge)
+    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() {
@@ -59,32 +120,19 @@ class ProginnBridge {
     window[root][name] = cb
   }
 
-  syncCookies() {
-    const app = cookies.get(COOKIE_APP_KEY)
-    const token = cookies.get(COOKIE_ACCESS_TOKEN_KEY)
-    const opts = {
-      domain: COOKIE_ROOT_DOMAIN,
-      expires: 7200
-    }
-
-    if (app) {
-      cookies.set(COOKIE_APP_KEY, app, opts)
-    }
-
-    if (token) {
-      cookies.set(COOKIE_ACCESS_TOKEN_KEY, token, opts)
-    }
-  }
-
   invoke(fn: string, payload?: any) {
     if (!this.root) {
       // tslint:disable-next-line
       console.warn(`Bridge invoke ${fn} skipped.`)
-      return
+      return null
     }
 
     if (this.isAndroid) {
-      return this.root[fn] && this.root[fn](payload)
+      if (typeof this.root[fn] === 'function') {
+        return payload ? this.root[fn](payload) : this.root[fn]()
+      } else {
+        return null
+      }
     } else {
       return this.root(fn, payload)
     }
@@ -102,6 +150,14 @@ class ProginnBridge {
     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
@@ -120,6 +176,54 @@ class ProginnBridge {
     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)
+      }
+    }
+  }
+
+  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)
+      }
+    }
+  }
+
   userLoad(userInfo: any) {
     this.invoke('user_load', this.isAndroid ? userInfo : {
       userInfo

+ 1 - 1
src/request/index.ts

@@ -4,7 +4,7 @@ import ProginnBridge from '../bridge'
 import { Notifier } from '../types/global'
 
 const factory = (opts: {
-  baseURL: string
+  baseURL?: string
   bridge?: ProginnBridge
   notifier?: Notifier
 }) => {

+ 4 - 0
src/types/global.ts

@@ -1 +1,5 @@
 export type Notifier = (msg: string, status?: string | number, resOrErr?: any) => void
+export type SyncCookiesOptions = {
+  domain?: string
+  expires?: number // d
+}

+ 5 - 0
yarn.lock

@@ -43,6 +43,11 @@ querystring@^0.2.0:
   resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
   integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
 
+semver@^7.3.2:
+  version "7.3.2"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
+  integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
+
 typescript@^3.9.7:
   version "3.9.7"
   resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"