Skip to content

Commit 41ae672

Browse files
committed
fix: handle app crashes the same as hmr sync failures in order to allow app recovery
1 parent d2d9d1f commit 41ae672

File tree

5 files changed

+37
-10
lines changed

5 files changed

+37
-10
lines changed

lib/common/constants.ts

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export class EmulatorDiscoveryNames {
5454

5555
export const DEVICE_LOG_EVENT_NAME = "deviceLogData";
5656
export const IOS_LOG_PREDICATE = 'senderImagePath contains "NativeScript" || eventMessage contains[c] "NativeScript"';
57+
export const IOS_APP_CRASH_LOG_REG_EXP = /Fatal JavaScript exception \- application has been terminated/;
5758

5859
export const TARGET_FRAMEWORK_IDENTIFIERS = {
5960
Cordova: "Cordova",
+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
interface IHmrStatusService {
2+
watchHmrStatus(deviceId: string, operationHash: string): void;
23
getHmrStatus(deviceId: string, operationHash: string): Promise<number>;
34
attachToHmrStatusEvent(): void;
45
}

lib/services/hmr-status-service.ts

+25-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { cache } from "../common/decorators";
2-
import { HmrConstants } from "../common/constants";
2+
import { HmrConstants, IOS_APP_CRASH_LOG_REG_EXP } from "../common/constants";
33

44
export class HmrStatusService implements IHmrStatusService {
55
public static HMR_STATUS_LOG_REGEX = /([a-z A-Z]*) hmr hash ([a-z0-9]*)\./;
@@ -11,9 +11,10 @@ export class HmrStatusService implements IHmrStatusService {
1111

1212
constructor(private $logParserService: ILogParserService,
1313
private $processService: IProcessService,
14+
private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
1415
private $logger: ILogger) {
15-
this.$processService.attachToProcessExitSignals(this, this.dispose);
16-
}
16+
this.$processService.attachToProcessExitSignals(this, this.dispose);
17+
}
1718

1819
public getHmrStatus(deviceId: string, operationHash: string): Promise<number> {
1920
return new Promise((resolve, reject) => {
@@ -33,13 +34,32 @@ export class HmrStatusService implements IHmrStatusService {
3334
});
3435
}
3536

37+
public watchHmrStatus(deviceId: string, operationHash: string): void {
38+
this.setData(deviceId, operationHash);
39+
}
40+
3641
@cache()
3742
public attachToHmrStatusEvent(): void {
3843
this.$logParserService.addParseRule({
3944
regex: HmrStatusService.HMR_STATUS_LOG_REGEX,
4045
handler: this.handleHmrStatusFound.bind(this),
4146
name: "hmrStatus"
4247
});
48+
this.$logParserService.addParseRule({
49+
regex: IOS_APP_CRASH_LOG_REG_EXP,
50+
handler: this.handleAppCrash.bind(this),
51+
name: "appCrashHmr",
52+
platform: this.$devicePlatformsConstants.iOS.toLowerCase()
53+
});
54+
}
55+
56+
private handleAppCrash(matches: RegExpMatchArray, deviceId: string): void {
57+
for (const operationId in this.hashOperationStatuses) {
58+
const operation = this.hashOperationStatuses[operationId];
59+
if (operationId.startsWith(deviceId) && !operation.status) {
60+
operation.status = HmrConstants.HMR_ERROR_STATUS;
61+
}
62+
}
4363
}
4464

4565
private handleHmrStatusFound(matches: RegExpMatchArray, deviceId: string): void {
@@ -65,7 +85,7 @@ export class HmrStatusService implements IHmrStatusService {
6585
this.$logger.trace("Found hmr status.", { status, hash });
6686

6787
if (status) {
68-
this.setData(status, hash, deviceId);
88+
this.setData(deviceId, hash, status);
6989
}
7090
}
7191

@@ -77,7 +97,7 @@ export class HmrStatusService implements IHmrStatusService {
7797
return null;
7898
}
7999

80-
private setData(status: Number, operationHash: string, deviceId: string): void {
100+
private setData(deviceId: string, operationHash: string, status?: Number): void {
81101
const key = `${deviceId}${operationHash}`;
82102

83103
if (!this.hashOperationStatuses[key]) {

lib/services/ios-debugger-port-service.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import { DEBUGGER_PORT_FOUND_EVENT_NAME, ATTACH_REQUEST_EVENT_NAME } from "../common/constants";
1+
import { DEBUGGER_PORT_FOUND_EVENT_NAME, ATTACH_REQUEST_EVENT_NAME, IOS_APP_CRASH_LOG_REG_EXP } from "../common/constants";
22
import { cache } from "../common/decorators";
33
import { APPLICATION_RESPONSE_TIMEOUT_SECONDS } from "../constants";
44

55
export class IOSDebuggerPortService implements IIOSDebuggerPortService {
66
public static DEBUG_PORT_LOG_REGEX = /NativeScript debugger has opened inspector socket on port (\d+?) for (.*)[.]/;
7-
public static APP_CRASH_LOG_REGEX = /Fatal JavaScript exception \- application has been terminated/;
87
private mapDebuggerPortData: IDictionary<IIOSDebuggerPortStoredData> = {};
98
private currentAppId: string;
109

@@ -51,12 +50,13 @@ export class IOSDebuggerPortService implements IIOSDebuggerPortService {
5150
platform: this.$devicePlatformsConstants.iOS.toLowerCase()
5251
});
5352
this.$logParserService.addParseRule({
54-
regex: IOSDebuggerPortService.APP_CRASH_LOG_REGEX,
53+
regex: IOS_APP_CRASH_LOG_REG_EXP,
5554
handler: this.handleAppCrash.bind(this),
5655
name: "appCrash",
5756
platform: this.$devicePlatformsConstants.iOS.toLowerCase()
5857
});
5958
}
59+
6060
private handleAppCrash(matches: RegExpMatchArray, deviceId: string): void {
6161
const data = {
6262
port: 0,

lib/services/livesync/livesync-service.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -664,12 +664,17 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi
664664
const service = this.getLiveSyncService(device.deviceInfo.platform);
665665

666666
const watchAction = async (watchInfo: ILiveSyncWatchInfo): Promise<void> => {
667+
const isInHMRMode = liveSyncData.useHotModuleReload && platformHmrData.hash;
668+
if (isInHMRMode) {
669+
this.$hmrStatusService.watchHmrStatus(device.deviceInfo.identifier, platformHmrData.hash);
670+
}
671+
667672
let liveSyncResultInfo = await service.liveSyncWatchAction(device, watchInfo);
668673

669674
await this.refreshApplication(projectData, liveSyncResultInfo, deviceBuildInfoDescriptor.debugOptions, deviceBuildInfoDescriptor.outputPath);
670675

671-
// If didRecover is true, this means we were in ErrorActivity and fallback files were already transfered and app will be restarted.
672-
if (!liveSyncResultInfo.didRecover && liveSyncData.useHotModuleReload && platformHmrData.hash) {
676+
// If didRecover is true, this means we were in ErrorActivity and fallback files were already transferred and app will be restarted.
677+
if (!liveSyncResultInfo.didRecover && isInHMRMode) {
673678
const status = await this.$hmrStatusService.getHmrStatus(device.deviceInfo.identifier, platformHmrData.hash);
674679
if (status === HmrConstants.HMR_ERROR_STATUS) {
675680
watchInfo.filesToSync = platformHmrData.fallbackFiles;

0 commit comments

Comments
 (0)