package com.tns; import java.io.File; import android.app.Application; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Build; import android.util.Log; import java.io.IOException; public final class RuntimeHelper { private RuntimeHelper() { } private static AndroidJsV8Inspector v8Inspector; // hasErrorIntent tells you if there was an event (with an uncaught // exception) raised from ErrorReport private static boolean hasErrorIntent(Application app) { boolean hasErrorIntent = false; try { // empty file just to check if there was a raised uncaught error by // ErrorReport if (Util.isDebuggableApp(app)) { String fileName = ""; try { java.lang.Class ErrReport = java.lang.Class.forName("com.tns.ErrorReport"); java.lang.reflect.Field field = ErrReport.getDeclaredField("ERROR_FILE_NAME"); fileName = (String)field.get(null); } catch (Exception e) { return false; } File errFile = new File(app.getFilesDir(), fileName); if (errFile.exists()) { errFile.delete(); hasErrorIntent = true; } } } catch (Exception e) { Log.d(logTag, e.getMessage()); } return hasErrorIntent; } public static Runtime initRuntime(Application app) { if (Runtime.isInitialized()) { return Runtime.getCurrentRuntime(); } System.loadLibrary("NativeScript"); Logger logger = new LogcatLogger(app); Runtime runtime = null; boolean showErrorIntent = hasErrorIntent(app); if (!showErrorIntent) { NativeScriptUncaughtExceptionHandler exHandler = new NativeScriptUncaughtExceptionHandler(logger, app); Thread.setDefaultUncaughtExceptionHandler(exHandler); DefaultExtractPolicy extractPolicy = new DefaultExtractPolicy(logger); boolean skipAssetExtraction = Util.runPlugin(logger, app); String appName = app.getPackageName(); File rootDir = new File(app.getApplicationInfo().dataDir); File appDir = app.getFilesDir(); try { appDir = appDir.getCanonicalFile(); } catch (IOException e1) { } if (!skipAssetExtraction) { if (logger.isEnabled()) { logger.write("Extracting assets..."); } AssetExtractor aE = new AssetExtractor(null, logger); String outputDir = app.getFilesDir().getPath() + File.separator; aE.extractAssets(app, "app", outputDir, extractPolicy); aE.extractAssets(app, "internal", outputDir, extractPolicy); aE.extractAssets(app, "metadata", outputDir, extractPolicy); // enable with flags? boolean shouldExtractSnapshots = true; // will extract snapshot of the device appropriate architecture if (shouldExtractSnapshots) { if (logger.isEnabled()) { logger.write("Extracting snapshot blob"); } aE.extractAssets(app, "snapshots/" + Build.CPU_ABI, outputDir, extractPolicy); } extractPolicy.setAssetsThumb(app); } AppConfig appConfig = new AppConfig(appDir); ClassLoader classLoader = app.getClassLoader(); File dexDir = new File(rootDir, "code_cache/secondary-dexes"); String dexThumb = null; try { dexThumb = Util.getDexThumb(app); } catch (NameNotFoundException e) { if (logger.isEnabled()) { logger.write("Error while getting current proxy thumb"); } e.printStackTrace(); } String nativeLibDir = null; try { nativeLibDir = app.getPackageManager().getApplicationInfo(appName, 0).nativeLibraryDir; } catch (android.content.pm.PackageManager.NameNotFoundException e) { e.printStackTrace(); } boolean isDebuggable = Util.isDebuggableApp(app); StaticConfiguration config = new StaticConfiguration(logger, appName, nativeLibDir, rootDir, appDir, classLoader, dexDir, dexThumb, appConfig, isDebuggable); runtime = Runtime.initializeRuntimeWithConfiguration(config); if (isDebuggable) { try { v8Inspector = new AndroidJsV8Inspector(app, logger); v8Inspector.start(); // the following snippet is used as means to notify the VSCode extension // debugger that the debugger agent has started File debugBreakFile = new File("/data/local/tmp", app.getPackageName() + "-debugger-started"); if (debugBreakFile.exists() && !debugBreakFile.isDirectory() && debugBreakFile.length() == 0) { java.io.FileWriter fileWriter = new java.io.FileWriter(debugBreakFile); fileWriter.write("started"); fileWriter.close(); } } catch (IOException e) { e.printStackTrace(); } } // runtime needs to be initialized before the NativeScriptSyncService is enabled because it uses runtime.runScript(...) if (NativeScriptSyncService.isSyncEnabled(app)) { NativeScriptSyncService syncService = new NativeScriptSyncService(runtime, logger, app); syncService.sync(); syncService.startServer(); // preserve this instance as strong reference // do not preserve in NativeScriptApplication field inorder to // make the code more portable // @@@ // Runtime.getOrCreateJavaObjectID(syncService); } else { if (logger.isEnabled()) { logger.write("NativeScript LiveSync is not enabled."); } } runtime.runScript(new File(appDir, "internal/ts_helpers.js")); File javaClassesModule = new File(appDir, "app/tns-java-classes.js"); if (javaClassesModule.exists()) { runtime.runModule(javaClassesModule); } try { // put this call in a try/catch block because with the latest changes in the modules it is not granted that NativeScriptApplication is extended through JavaScript. JavaScriptImplementation jsImpl = app.getClass().getAnnotation(JavaScriptImplementation.class); if (jsImpl != null) { Runtime.initInstance(app); } } catch (Exception e) { if (logger.isEnabled()) { logger.write("Cannot initialize application instance."); } e.printStackTrace(); } } return runtime; } private static final String logTag = "MyApp"; }