@mpxjs/core 2.9.70-alpha.1 → 2.9.70-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  // declaration for mpx mode
2
- declare let __mpx_mode__: 'wx' | 'ali' | 'swan' | 'qq' | 'tt' | 'dd' | 'qa' | 'jd' | 'web' | 'tenon'
2
+ declare let __mpx_mode__: 'wx' | 'ali' | 'swan' | 'qq' | 'tt' | 'web' | 'dd' | 'qa' | 'jd' | 'android' | 'ios' | 'harmony' | 'tenon'
3
3
 
4
4
  // declaration for mpx env
5
5
  declare let __mpx_env__: string
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpxjs/core",
3
- "version": "2.9.70-alpha.1",
3
+ "version": "2.9.70-alpha.3",
4
4
  "description": "mpx runtime core",
5
5
  "keywords": [
6
6
  "miniprogram",
@@ -19,12 +19,11 @@
19
19
  ],
20
20
  "main": "src/index.js",
21
21
  "dependencies": {
22
- "@mpxjs/utils": ">=2.9.69-alpha",
22
+ "@mpxjs/utils": "2.9.70-alpha.0",
23
23
  "lodash": "^4.1.1",
24
24
  "miniprogram-api-typings": "^3.10.0"
25
25
  },
26
26
  "peerDependencies": {
27
- "@ant-design/react-native": "^5.1.3",
28
27
  "@d11/react-native-fast-image": "^8.6.12",
29
28
  "@hummer/tenon-store": "^1.7.0",
30
29
  "@hummer/tenon-vue": "^1.5.1",
@@ -35,6 +34,7 @@
35
34
  "react-native": "*",
36
35
  "react-native-gesture-handler": "^2.19.0",
37
36
  "react-native-linear-gradient": "^2.8.3",
37
+ "react-native-reanimated": "^3.15.2",
38
38
  "react-native-safe-area-context": "^4.14.0",
39
39
  "react-native-screens": "^4.1.0",
40
40
  "react-native-webview": "^13.10.5",
@@ -62,13 +62,13 @@
62
62
  "react-native": {
63
63
  "optional": true
64
64
  },
65
- "@react-navigation/native": {
65
+ "react-native-reanimated": {
66
66
  "optional": true
67
67
  },
68
- "@react-navigation/stack": {
68
+ "@react-navigation/native": {
69
69
  "optional": true
70
70
  },
71
- "@ant-design/react-native": {
71
+ "@react-navigation/native-stack": {
72
72
  "optional": true
73
73
  },
74
74
  "react-native-safe-area-context": {
@@ -5,7 +5,7 @@ import {
5
5
  import { implemented } from '../core/implement'
6
6
 
7
7
  // 暂不支持的wx选项,后期需要各种花式支持
8
- const unsupported = ['relations', 'moved', 'definitionFilter']
8
+ const unsupported = ['moved', 'definitionFilter']
9
9
 
10
10
  function convertErrorDesc (key) {
11
11
  error(`Options.${key} is not supported in runtime conversion from wx to react native.`, global.currentResource)
@@ -122,9 +122,10 @@ function extractObservers (options) {
122
122
  Object.keys(props).forEach(key => {
123
123
  const prop = props[key]
124
124
  if (prop && prop.observer) {
125
+ let callback = prop.observer
126
+ delete prop.observer
125
127
  mergeWatch(key, {
126
128
  handler (...rest) {
127
- let callback = prop.observer
128
129
  if (typeof callback === 'string') {
129
130
  callback = this[callback]
130
131
  }
@@ -168,11 +169,7 @@ function extractObservers (options) {
168
169
  cb = this[cb]
169
170
  }
170
171
  if (typeof cb === 'function') {
171
- if (keyPathArr.length < 2) {
172
- val = [val]
173
- old = [old]
174
- }
175
- cb.call(this, ...val, ...old)
172
+ Array.isArray(val) ? cb.call(this, ...val) : cb.call(this, val)
176
173
  }
177
174
  },
178
175
  deep,
package/src/core/proxy.js CHANGED
@@ -1,4 +1,4 @@
1
- import { reactive, shallowReactive } from '../observer/reactive'
1
+ import { reactive, defineReactive } from '../observer/reactive'
2
2
  import { ReactiveEffect, pauseTracking, resetTracking } from '../observer/effect'
3
3
  import { effectScope } from '../platform/export/index'
4
4
  import { watch } from '../observer/watch'
@@ -52,7 +52,7 @@ import {
52
52
  } from './innerLifecycle'
53
53
  import contextMap from '../dynamic/vnode/context'
54
54
  import { getAst } from '../dynamic/astCache'
55
- import { inject, provide } from '../platform/export/apiInject'
55
+ import { inject, provide } from '../platform/export/inject'
56
56
 
57
57
  let uid = 0
58
58
 
@@ -112,7 +112,7 @@ export default class MpxProxy {
112
112
  this.uid = uid++
113
113
  this.name = options.name || ''
114
114
  this.options = options
115
- this.ignoreReactivePattern = this.options.options?.ignoreReactivePattern
115
+ this.shallowReactivePattern = this.options.options?.shallowReactivePattern
116
116
  // beforeCreate -> created -> mounted -> unmounted
117
117
  this.state = BEFORECREATE
118
118
  this.ignoreProxyMap = makeMap(Mpx.config.ignoreProxyWhiteList)
@@ -146,10 +146,12 @@ export default class MpxProxy {
146
146
  this.initApi()
147
147
  }
148
148
 
149
- processIgnoreReactive (obj) {
150
- if (this.ignoreReactivePattern && isObject(obj)) {
149
+ processShallowReactive (obj) {
150
+ if (this.shallowReactivePattern && isObject(obj)) {
151
151
  Object.keys(obj).forEach((key) => {
152
- if (this.ignoreReactivePattern.test(key)) {
152
+ if (this.shallowReactivePattern.test(key)) {
153
+ // 命中shallowReactivePattern的属性将其设置为 shallowReactive
154
+ defineReactive(obj, key, obj[key], true)
153
155
  Object.defineProperty(obj, key, {
154
156
  enumerable: true,
155
157
  // set configurable to false to skip defineReactive
@@ -170,6 +172,8 @@ export default class MpxProxy {
170
172
  // web中BEFORECREATE钩子通过vue的beforeCreate钩子单独驱动
171
173
  this.callHook(BEFORECREATE)
172
174
  setCurrentInstance(this)
175
+ this.parent = this.resolveParent()
176
+ this.provides = this.parent ? this.parent.provides : Object.create(null)
173
177
  // 在 props/data 初始化之前初始化 inject
174
178
  this.initInject()
175
179
  this.initProps()
@@ -194,6 +198,18 @@ export default class MpxProxy {
194
198
  }
195
199
  }
196
200
 
201
+ resolveParent () {
202
+ if (isReact) {
203
+ return {
204
+ provides: this.target.__parentProvides
205
+ }
206
+ }
207
+ if (isFunction(this.target.selectOwnerComponent)) {
208
+ const parent = this.target.selectOwnerComponent()
209
+ return parent ? parent.__mpxProxy : null
210
+ }
211
+ }
212
+
197
213
  createRenderTask (isEmptyRender) {
198
214
  if ((!this.isMounted() && this.currentRenderTask) || (this.isMounted() && isEmptyRender)) {
199
215
  return
@@ -233,16 +249,6 @@ export default class MpxProxy {
233
249
  // 页面/组件销毁清除上下文的缓存
234
250
  contextMap.remove(this.uid)
235
251
  }
236
- if (!isWeb && this.options.__type__ === 'page') {
237
- // 小程序页面销毁时移除对应的 provide
238
- if (isFunction(this.target.getPageId)) {
239
- const pageId = this.target.getPageId()
240
- const providesMap = global.__mpxProvidesMap
241
- if (providesMap.__pages[pageId]) {
242
- delete providesMap.__pages[pageId]
243
- }
244
- }
245
- }
246
252
  this.callHook(BEFOREUNMOUNT)
247
253
  this.scope?.stop()
248
254
  if (this.update) this.update.active = false
@@ -291,10 +297,10 @@ export default class MpxProxy {
291
297
  if (isReact) {
292
298
  // react模式下props内部对象透传无需深clone,依赖对象深层的数据响应触发子组件更新
293
299
  this.props = this.target.__getProps()
294
- shallowReactive(this.processIgnoreReactive(this.props))
300
+ reactive(this.processShallowReactive(this.props))
295
301
  } else {
296
302
  this.props = diffAndCloneA(this.target.__getProps(this.options)).clone
297
- reactive(this.processIgnoreReactive(this.props))
303
+ reactive(this.processShallowReactive(this.props))
298
304
  }
299
305
  proxy(this.target, this.props, undefined, false, this.createProxyConflictHandler('props'))
300
306
  }
@@ -334,7 +340,7 @@ export default class MpxProxy {
334
340
  if (isFunction(dataFn)) {
335
341
  Object.assign(this.data, callWithErrorHandling(dataFn.bind(this.target), this, 'data function'))
336
342
  }
337
- reactive(this.processIgnoreReactive(this.data))
343
+ reactive(this.processShallowReactive(this.data))
338
344
  proxy(this.target, this.data, undefined, false, this.createProxyConflictHandler('data'))
339
345
  this.collectLocalKeys(this.data)
340
346
  }
@@ -515,7 +521,7 @@ export default class MpxProxy {
515
521
  if (hasOwn(renderData, key)) {
516
522
  const data = renderData[key]
517
523
  const firstKey = getFirstKey(key)
518
- if (!this.localKeysMap[firstKey] || (this.ignoreReactivePattern && this.ignoreReactivePattern.test(firstKey))) {
524
+ if (!this.localKeysMap[firstKey]) {
519
525
  continue
520
526
  }
521
527
  // 外部clone,用于只需要clone的场景
@@ -762,7 +768,7 @@ export default class MpxProxy {
762
768
  }
763
769
  setByPath(this.target, key, data[key])
764
770
  })
765
- this.forceUpdateData = data
771
+ Object.assign(this.forceUpdateData, data)
766
772
  } else {
767
773
  this.forceUpdateAll = true
768
774
  }
package/src/index.js CHANGED
@@ -1,8 +1,7 @@
1
- import Vue from './external/vue'
1
+
2
2
  import { error, diffAndCloneA, hasOwn, makeMap } from '@mpxjs/utils'
3
3
  import { APIs, InstanceAPIs } from './platform/export/api'
4
-
5
- import { createI18n } from './platform/builtInMixins/i18nMixin'
4
+ import { init } from './platform/env/index'
6
5
 
7
6
  export * from './platform/export/index'
8
7
 
@@ -156,12 +155,6 @@ Mpx.config = {
156
155
  rnConfig: {}
157
156
  }
158
157
 
159
- global.__mpx = Mpx
160
-
161
- if (__mpx_mode__ !== 'web') {
162
- if (global.i18n) {
163
- Mpx.i18n = createI18n(global.i18n)
164
- }
165
- }
158
+ init(Mpx)
166
159
 
167
160
  export default Mpx
@@ -34,6 +34,7 @@ export class Observer {
34
34
 
35
35
  constructor (value, shallow) {
36
36
  this.value = value
37
+ this.shallow = shallow
37
38
  def(value, ObKey, this)
38
39
  if (Array.isArray(value)) {
39
40
  const augment = hasProto && arrayProtoAugment
@@ -120,7 +121,7 @@ export function defineReactive (obj, key, val, shallow) {
120
121
  const getter = property && property.get
121
122
  const setter = property && property.set
122
123
 
123
- let childOb = !shallow && observe(val)
124
+ let childOb = shallow ? getObserver(val) : observe(val)
124
125
  Object.defineProperty(obj, key, {
125
126
  enumerable: true,
126
127
  configurable: true,
@@ -149,7 +150,7 @@ export function defineReactive (obj, key, val, shallow) {
149
150
  } else {
150
151
  val = newVal
151
152
  }
152
- childOb = !shallow && observe(newVal)
153
+ childOb = shallow ? getObserver(newVal) : observe(newVal)
153
154
  dep.notify()
154
155
  }
155
156
  })
@@ -175,7 +176,7 @@ export function set (target, key, val) {
175
176
  target[key] = val
176
177
  return val
177
178
  }
178
- defineReactive(ob.value, key, val)
179
+ defineReactive(ob.value, key, val, ob.shallow)
179
180
  ob.dep.notify()
180
181
  return val
181
182
  }
@@ -1,7 +1,10 @@
1
1
  export default function directiveHelperMixin () {
2
2
  return {
3
3
  methods: {
4
- __getWxKey (item, key) {
4
+ __getWxKey (item, key, index) {
5
+ if (key === 'index') {
6
+ return index
7
+ }
5
8
  return key === '*this' ? item : item[key]
6
9
  }
7
10
  }
@@ -22,7 +22,8 @@ export default function getBuiltInMixins ({ type, rawOptions = {} }) {
22
22
  directiveHelperMixin(),
23
23
  styleHelperMixin(),
24
24
  refsMixin(),
25
- i18nMixin()
25
+ i18nMixin(),
26
+ relationsMixin(type)
26
27
  ]
27
28
  } else if (__mpx_mode__ === 'web') {
28
29
  bulitInMixins = [
@@ -1,4 +1,5 @@
1
- import { setByPath } from '@mpxjs/utils'
1
+ import { setByPath, error, parseDataset } from '@mpxjs/utils'
2
+ import Mpx from '../../index'
2
3
 
3
4
  export default function proxyEventMixin () {
4
5
  return {
@@ -19,11 +20,58 @@ export default function proxyEventMixin () {
19
20
  const value = filterMethod ? (innerFilter[filterMethod] ? innerFilter[filterMethod](originValue) : typeof this[filterMethod] === 'function' && this[filterMethod]) : originValue
20
21
  setByPath(this, expr, value)
21
22
  },
22
- __invokeHandler (eventName, $event) {
23
- const handler = this[eventName]
24
- if (handler && typeof handler === 'function') {
25
- handler.call(this, $event)
23
+ __invoke (rawEvent, eventConfig = []) {
24
+ if (typeof Mpx.config.proxyEventHandler === 'function') {
25
+ try {
26
+ Mpx.config.proxyEventHandler(rawEvent)
27
+ } catch (e) {}
26
28
  }
29
+ const location = this.__mpxProxy.options.mpxFileResource
30
+
31
+ if (rawEvent.target && !rawEvent.target._datasetProcessed) {
32
+ const originalDataset = rawEvent.target.dataset
33
+ Object.defineProperty(rawEvent.target, 'dataset', {
34
+ get: () => parseDataset(originalDataset),
35
+ configurable: true,
36
+ enumerable: true
37
+ })
38
+ rawEvent.target._datasetProcessed = true
39
+ }
40
+ if (rawEvent.currentTarget && !rawEvent.currentTarget._datasetProcessed) {
41
+ const originalDataset = rawEvent.currentTarget.dataset
42
+ Object.defineProperty(rawEvent.currentTarget, 'dataset', {
43
+ get: () => parseDataset(originalDataset),
44
+ configurable: true,
45
+ enumerable: true
46
+ })
47
+ rawEvent.currentTarget._datasetProcessed = true
48
+ }
49
+
50
+ let returnedValue
51
+ eventConfig.forEach((item) => {
52
+ const callbackName = item[0]
53
+ if (callbackName) {
54
+ const params =
55
+ item.length > 1
56
+ ? item.slice(1).map((item) => {
57
+ if (item === '__mpx_event__') {
58
+ return rawEvent
59
+ } else {
60
+ return item
61
+ }
62
+ })
63
+ : [rawEvent]
64
+ if (typeof this[callbackName] === 'function') {
65
+ returnedValue = this[callbackName].apply(this, params)
66
+ } else {
67
+ error(
68
+ `Instance property [${callbackName}] is not function, please check.`,
69
+ location
70
+ )
71
+ }
72
+ }
73
+ })
74
+ return returnedValue
27
75
  }
28
76
  }
29
77
  }
@@ -0,0 +1,67 @@
1
+ import { BEFORECREATE, MOUNTED, BEFOREUNMOUNT } from '../../core/innerLifecycle'
2
+
3
+ const relationTypeMap = {
4
+ parent: 'child',
5
+ ancestor: 'descendant'
6
+ }
7
+
8
+ export default function relationsMixin (mixinType) {
9
+ if (mixinType === 'component') {
10
+ return {
11
+ [BEFORECREATE] () {
12
+ this.__relationNodesMap = {}
13
+ },
14
+ [MOUNTED] () {
15
+ this.__mpxExecRelations('linked')
16
+ },
17
+ [BEFOREUNMOUNT] () {
18
+ this.__mpxExecRelations('unlinked')
19
+ this.__relationNodesMap = {}
20
+ },
21
+ methods: {
22
+ getRelationNodes (path) {
23
+ return this.__relationNodesMap[path] || null
24
+ },
25
+ __mpxExecRelations (type) {
26
+ const relations = this.__mpxProxy.options.relations
27
+ const relationContext = this.__relation
28
+ const currentPath = this.__componentPath
29
+ if (relations && relationContext) {
30
+ Object.keys(relations).forEach((path) => {
31
+ const relation = relations[path]
32
+ const relationType = relation.type
33
+ if ((relationType === 'parent' || relationType === 'ancestor') && relationContext[path]) {
34
+ const target = relationContext[path]
35
+ const targetRelation = target.__mpxProxy.options.relations?.[currentPath]
36
+ if (targetRelation && targetRelation.type === relationTypeMap[relationType] && target.__componentPath === path) {
37
+ if (type === 'linked') {
38
+ this.__mpxLinkRelationNodes(target, currentPath)
39
+ } else if (type === 'unlinked') {
40
+ this.__mpxRemoveRelationNodes(target, currentPath)
41
+ }
42
+ if (typeof targetRelation[type] === 'function') {
43
+ targetRelation[type].call(target, this)
44
+ }
45
+ if (typeof relation[type] === 'function') {
46
+ relation[type].call(this, target)
47
+ }
48
+ this.__relationNodesMap[path] = [target]
49
+ }
50
+ }
51
+ })
52
+ }
53
+ },
54
+ __mpxLinkRelationNodes (target, path) {
55
+ target.__relationNodesMap[path] = target.__relationNodesMap[path] || [] // 父级绑定子级
56
+ target.__relationNodesMap[path].push(this)
57
+ },
58
+ __mpxRemoveRelationNodes (target, path) {
59
+ const relationNodesMap = target.__relationNodesMap
60
+ const arr = relationNodesMap[path] || []
61
+ const index = arr.indexOf(this)
62
+ if (index !== -1) arr.splice(index, 1)
63
+ }
64
+ }
65
+ }
66
+ }
67
+ }
@@ -181,7 +181,7 @@ export default function styleHelperMixin () {
181
181
  } else if (appClassMap[className]) {
182
182
  // todo 全局样式在每个页面和组件中生效,以支持全局原子类,后续支持样式模块复用后可考虑移除
183
183
  Object.assign(result, appClassMap[className])
184
- } else if (this.__props[className] && isObject(this.__props[className])) {
184
+ } else if (isObject(this.__props[className])) {
185
185
  // externalClasses必定以对象形式传递下来
186
186
  Object.assign(result, this.__props[className])
187
187
  }
@@ -1,12 +1,12 @@
1
1
  import transferOptions from '../core/transferOptions'
2
2
  import builtInKeysMap from './patch/builtInKeysMap'
3
- import { makeMap, spreadProp, parseUrlQuery, getFocusedNavigation, hasOwn, extend } from '@mpxjs/utils'
3
+ import { makeMap, spreadProp, getFocusedNavigation, hasOwn } from '@mpxjs/utils'
4
4
  import { mergeLifecycle } from '../convertor/mergeLifecycle'
5
5
  import { LIFECYCLE } from '../platform/patch/lifecycle/index'
6
6
  import Mpx from '../index'
7
7
  import { createElement, memo, useRef, useEffect } from 'react'
8
8
  import * as ReactNative from 'react-native'
9
- import { ref } from '../observer/ref'
9
+ import { initAppProvides } from './export/inject'
10
10
 
11
11
  const appHooksMap = makeMap(mergeLifecycle(LIFECYCLE).app)
12
12
 
@@ -29,22 +29,28 @@ function filterOptions (options, appData) {
29
29
  return newOptions
30
30
  }
31
31
 
32
- function createAppInstance (appData) {
33
- return extend({}, Mpx.prototype, appData)
34
- }
35
-
36
- export default function createApp (option, config = {}) {
32
+ export default function createApp (options) {
37
33
  const appData = {}
38
34
 
39
35
  const { NavigationContainer, createStackNavigator, SafeAreaProvider } = global.__navigationHelper
40
36
  // app选项目前不需要进行转换
41
- const { rawOptions, currentInject } = transferOptions(option, 'app', false)
37
+ const { rawOptions, currentInject } = transferOptions(options, 'app', false)
38
+ initAppProvides(rawOptions.provide, rawOptions)
42
39
  const defaultOptions = filterOptions(spreadProp(rawOptions, 'methods'), appData)
43
- defaultOptions.onAppInit && defaultOptions.onAppInit()
44
40
  // 在页面script执行前填充getApp()
45
41
  global.getApp = function () {
46
42
  return appData
47
43
  }
44
+
45
+ // 模拟小程序appInstance在热启动时不会重新创建的行为,在外部创建跟随js context的appInstance
46
+ const appInstance = Object.assign({}, appData, Mpx.prototype)
47
+
48
+ defaultOptions.onShow && global.__mpxAppCbs.show.push(defaultOptions.onShow.bind(appInstance))
49
+ defaultOptions.onHide && global.__mpxAppCbs.hide.push(defaultOptions.onHide.bind(appInstance))
50
+ defaultOptions.onError && global.__mpxAppCbs.error.push(defaultOptions.onError.bind(appInstance))
51
+ defaultOptions.onUnhandledRejection && global.__mpxAppCbs.rejection.push(defaultOptions.onUnhandledRejection.bind(appInstance))
52
+ defaultOptions.onAppInit && defaultOptions.onAppInit()
53
+
48
54
  const pages = currentInject.getPages() || {}
49
55
  const firstPage = currentInject.firstPage
50
56
  const Stack = createStackNavigator()
@@ -80,63 +86,51 @@ export default function createApp (option, config = {}) {
80
86
  }
81
87
  }
82
88
 
83
- global.__mpxAppCbs = global.__mpxAppCbs || {
84
- show: [],
85
- hide: [],
86
- error: []
87
- }
88
-
89
89
  global.__mpxAppLaunched = false
90
-
91
- global.__mpxAppFocusedState = ref('show')
92
90
  global.__mpxOptionsMap[currentInject.moduleId] = memo((props) => {
93
- const instanceRef = useRef(null)
94
- if (!instanceRef.current) {
95
- instanceRef.current = createAppInstance(appData)
96
- }
97
- const instance = instanceRef.current
91
+ const firstRef = useRef(true)
98
92
  const initialRouteRef = useRef({
99
93
  initialRouteName: firstPage,
100
94
  initialParams: {}
101
95
  })
96
+ if (firstRef.current) {
97
+ // 热启动情况下,app会被销毁重建,将__mpxAppHotLaunched重置保障路由等初始化逻辑正确执行
98
+ global.__mpxAppHotLaunched = false
99
+ // 热启动情况下重置__mpxPagesMap避免页面销毁函数未及时执行时错误地引用到之前的navigation
100
+ global.__mpxPagesMap = {}
101
+ firstRef.current = false
102
+ }
103
+ if (!global.__mpxAppHotLaunched) {
104
+ const { initialRouteName, initialParams } = Mpx.config.rnConfig.parseAppProps?.(props) || {}
105
+ initialRouteRef.current.initialRouteName = initialRouteName || initialRouteRef.current.initialRouteName
106
+ initialRouteRef.current.initialParams = initialParams || initialRouteRef.current.initialParams
102
107
 
103
- if (!global.__mpxAppLaunched) {
104
- const parsed = Mpx.config.rnConfig.parseAppProps?.(props) || {}
105
- if (parsed.url) {
106
- const { path, queryObj } = parseUrlQuery(parsed.url)
107
- Object.assign(initialRouteRef.current, {
108
- initialRouteName: path.startsWith('/') ? path.slice(1) : path,
109
- initialParams: queryObj
110
- })
111
- }
112
108
  global.__mpxAppOnLaunch = (navigation) => {
113
- global.__mpxAppLaunched = true
114
109
  const state = navigation.getState()
115
110
  Mpx.config.rnConfig.onStateChange?.(state)
116
111
  const current = state.routes[state.index]
117
- global.__mpxEnterOptions = {
112
+ const options = {
118
113
  path: current.name,
119
114
  query: current.params,
120
115
  scene: 0,
121
116
  shareTicket: '',
122
- referrerInfo: {}
117
+ referrerInfo: {},
118
+ isLaunch: true
119
+ }
120
+ global.__mpxEnterOptions = options
121
+ if (!global.__mpxAppLaunched) {
122
+ global.__mpxLaunchOptions = options
123
+ defaultOptions.onLaunch && defaultOptions.onLaunch.call(appInstance, options)
123
124
  }
124
- defaultOptions.onLaunch && defaultOptions.onLaunch.call(instance, global.__mpxEnterOptions)
125
- defaultOptions.onShow && defaultOptions.onShow.call(instance, global.__mpxEnterOptions)
125
+ global.__mpxAppCbs.show.forEach((cb) => {
126
+ cb(options)
127
+ })
128
+ global.__mpxAppLaunched = true
129
+ global.__mpxAppHotLaunched = true
126
130
  }
127
131
  }
128
132
 
129
133
  useEffect(() => {
130
- if (defaultOptions.onShow) {
131
- global.__mpxAppCbs.show.push(defaultOptions.onShow.bind(instance))
132
- }
133
- if (defaultOptions.onHide) {
134
- global.__mpxAppCbs.hide.push(defaultOptions.onHide.bind(instance))
135
- }
136
- if (defaultOptions.onError) {
137
- global.__mpxAppCbs.error.push(defaultOptions.onError.bind(instance))
138
- }
139
-
140
134
  const changeSubscription = ReactNative.AppState.addEventListener('change', (currentState) => {
141
135
  if (currentState === 'active') {
142
136
  let options = global.__mpxEnterOptions
@@ -158,7 +152,7 @@ export default function createApp (option, config = {}) {
158
152
  if (navigation && hasOwn(global.__mpxPageStatusMap, navigation.pageId)) {
159
153
  global.__mpxPageStatusMap[navigation.pageId] = 'show'
160
154
  }
161
- } else if (currentState === 'inactive') {
155
+ } else if (currentState === 'inactive' || currentState === 'background') {
162
156
  global.__mpxAppCbs.hide.forEach((cb) => {
163
157
  cb()
164
158
  })
@@ -187,6 +181,19 @@ export default function createApp (option, config = {}) {
187
181
  }, [])
188
182
 
189
183
  const { initialRouteName, initialParams } = initialRouteRef.current
184
+ const headerBackImageSource = Mpx.config.rnConfig.headerBackImageSource || null
185
+ const navScreenOpts = {
186
+ // 7.x替换headerBackTitleVisible
187
+ // headerBackButtonDisplayMode: 'minimal',
188
+ headerBackTitleVisible: false,
189
+ // 安卓上会出现初始化时闪现导航条的问题
190
+ headerShown: false,
191
+ // 隐藏导航下的那条线
192
+ headerShadowVisible: false
193
+ }
194
+ if (headerBackImageSource) {
195
+ navScreenOpts.headerBackImageSource = headerBackImageSource
196
+ }
190
197
  return createElement(SafeAreaProvider,
191
198
  null,
192
199
  createElement(NavigationContainer,
@@ -197,13 +204,7 @@ export default function createApp (option, config = {}) {
197
204
  createElement(Stack.Navigator,
198
205
  {
199
206
  initialRouteName,
200
- screenOptions: {
201
- gestureEnabled: true,
202
- // 7.x替换headerBackTitleVisible
203
- // headerBackButtonDisplayMode: 'minimal',
204
- headerBackTitleVisible: false,
205
- headerMode: 'float'
206
- }
207
+ screenOptions: navScreenOpts
207
208
  },
208
209
  ...getPageScreens(initialRouteName, initialParams)
209
210
  )