index.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. import cookies from 'js-cookie';
  2. import semver from 'semver';
  3. 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';
  4. const parseJWT = (token) => {
  5. const payloadStr = token.split('.')[1];
  6. if (!payloadStr) {
  7. return null;
  8. }
  9. try {
  10. return JSON.parse(atob(payloadStr));
  11. }
  12. catch (e) {
  13. // tslint:disable-next-line
  14. console.error('[parseJWT]', e);
  15. }
  16. return null;
  17. };
  18. const getAppInfo = () => {
  19. const val = cookies.get(COOKIE_APP_KEY);
  20. const matched = val && /^(ios|android)\ ((?:\d\.?)+)$/.exec(val);
  21. if (!matched) {
  22. return null;
  23. }
  24. return {
  25. os: matched[1],
  26. version: matched[2]
  27. };
  28. };
  29. const getAppExtra = () => {
  30. const val = cookies.get(COOKIE_APP_EXTRA_KEY);
  31. const segments = val && val.split(/\s+/);
  32. if (!segments || !segments.length) {
  33. return {};
  34. }
  35. return segments.reduce((map, item) => {
  36. const matched = /^([0-9a-zA-Z_-]+)\/(.+)$/.exec(item);
  37. if (matched) {
  38. map[matched[1]] = matched[2];
  39. }
  40. return map;
  41. }, {});
  42. };
  43. let cachedAppInfo;
  44. let cachedappExtra;
  45. class ProginnBridge {
  46. constructor(opts) {
  47. // @ts-ignore
  48. this.root = window.app_event || window.appBridge;
  49. const { notifier } = opts || {};
  50. this.notifier = notifier;
  51. }
  52. get appInfo() {
  53. cachedAppInfo = cachedAppInfo || getAppInfo();
  54. return cachedAppInfo;
  55. }
  56. get appExtra() {
  57. cachedappExtra = cachedappExtra || getAppExtra();
  58. return cachedappExtra;
  59. }
  60. get appVersion() {
  61. var _a;
  62. return (_a = this.appInfo) === null || _a === void 0 ? void 0 : _a.version;
  63. }
  64. get os() {
  65. var _a;
  66. return (_a = this.appInfo) === null || _a === void 0 ? void 0 : _a.os;
  67. }
  68. get isInApp() {
  69. return !!(this.appInfo || this.root);
  70. }
  71. get isAndroid() {
  72. return /Android/.test(window.navigator.userAgent) || this.os === 'android' || false;
  73. }
  74. get isIos() {
  75. return /iP(hone|ad|od)/.test(window.navigator.userAgent) || this.os === 'ios' || false;
  76. }
  77. get cookie() {
  78. return cookies.get();
  79. }
  80. get isLogined() {
  81. return !!cookies.get(COOKIE_ACCESS_TOKEN_KEY);
  82. }
  83. get uid() {
  84. const token = cookies.get(COOKIE_ACCESS_TOKEN_KEY);
  85. const payload = token && parseJWT(token);
  86. return payload === null || payload === void 0 ? void 0 : payload.uid;
  87. }
  88. inject(name, cb, root = 'Proginn') {
  89. window[root] = window[root] || {};
  90. window[root][name] = cb;
  91. }
  92. invoke(fn, payload) {
  93. if (!this.root) {
  94. // tslint:disable-next-line
  95. console.warn(`Bridge invoke ${fn} skipped.`);
  96. return null;
  97. }
  98. if (this.isAndroid) {
  99. if (typeof this.root[fn] === 'function') {
  100. return payload ? this.root[fn](payload) : this.root[fn]();
  101. }
  102. else {
  103. return null;
  104. }
  105. }
  106. else {
  107. return this.root(fn, payload);
  108. }
  109. }
  110. back() {
  111. if (!this.isInApp) {
  112. window.history.back();
  113. }
  114. else {
  115. this.invoke('back_page');
  116. }
  117. }
  118. load(url) {
  119. window.location.href = url;
  120. }
  121. open(url, title) {
  122. if (this.isInApp && (!this.isAndroid || this.compareAppVersion('gte', '4.20.0'))) {
  123. url = `proginn://webview?url=${encodeURIComponent(url)}${title ? '&title=' + encodeURIComponent(title) : ''}`;
  124. }
  125. this.load(url);
  126. }
  127. login() {
  128. if (!this.isInApp) {
  129. return;
  130. }
  131. this.load('proginn://login?backToPage=true');
  132. }
  133. checkLogin(force = false) {
  134. if (force || !this.isLogined) {
  135. this.notifier && this.notifier(MSG_REQUIRE_LOGIN, -99);
  136. this.login();
  137. return false;
  138. }
  139. return true;
  140. }
  141. compareAppVersion(operator, version) {
  142. return this.appVersion ? semver[operator](this.appVersion, version) : false;
  143. }
  144. syncCookies(opts) {
  145. opts = opts || {};
  146. opts.domain = opts.domain || COOKIE_ROOT_DOMAIN;
  147. opts.expires = opts.expires || DEF_SYNCED_COOKIE_EXP;
  148. for (const key of APP_INJECT_COOKIE_KEYS) {
  149. const val = cookies.get(key);
  150. if (val) {
  151. cookies.set(key, val, opts);
  152. }
  153. }
  154. }
  155. // generally to fix android webview cookies non-inject bug
  156. cacheCookiesInStorage() {
  157. for (const key of APP_INJECT_COOKIE_KEYS) {
  158. const val = cookies.get(key);
  159. if (val) {
  160. window.localStorage.setItem(key, val);
  161. }
  162. else {
  163. window.localStorage.removeItem(key);
  164. }
  165. }
  166. }
  167. loadCookiesInStorage(opts) {
  168. opts = opts || {};
  169. opts.domain = opts.domain || COOKIE_ROOT_DOMAIN;
  170. opts.expires = opts.expires || DEF_SYNCED_COOKIE_EXP;
  171. for (const key of APP_INJECT_COOKIE_KEYS) {
  172. // pass if already exists
  173. if (cookies.get(key)) {
  174. continue;
  175. }
  176. const val = window.localStorage.getItem(key);
  177. if (val) {
  178. cookies.set(key, val, opts);
  179. }
  180. }
  181. }
  182. userLoad(userInfo) {
  183. this.invoke('user_load', this.isAndroid ? userInfo : {
  184. userInfo
  185. });
  186. }
  187. topicLoad(id, data) {
  188. this.invoke('topic_load', this.isAndroid ? id : data);
  189. }
  190. setNavigationBarTitle(title) {
  191. this.invoke('setNavigationBarTitle', title);
  192. }
  193. }
  194. export default ProginnBridge;