Where Is Main() in Android

Where is main() in Android?

Android uses the java language, but executes using a modified runtime model. As others have said, there is a manifest included in each package. The launchpoint is specified in this manifest. Go to the android site and do the basic tutorials. This will get you up and running with an understanding of create/deploy/run process and the basic app life cycle.

Why there is no main() method in android?

There's one, but you don't need to see it. Android takes care of threading and keeping threads organized for you, see here.

Moreover, the entry point for an activity is the onCreate() method, so all initialization is normally done in there. The first activity run by your app is normally specified in the manifest file under the launcher keyword.

See here to know more about how android runs the launcher activity.

Is there a function in Android analogous to int main in C/C++ which contains the program's main loop?

As far as an Android program is concerned there is no main().

There is a UI loop that the OS runs that makes calls to methods you define or override in your program. These methods are likely called from/defined in onCreate(), onStart(), onResume(), onReStart(), onPause(), onStop(), or onDestroy(). All these methods may be overriden in your program.

The fundamental issue is that the OS is designed to run in a resource constrained environment. Your program needs to be prepared to be halted and even completely stopped whenever the OS needs more memory (this is a multitasking OS). In order to handle that your program needs to have some of all of the functions listed above.

The Activity lifecycle describes this best (your program is one or more Activities, think of an Activity as a screen).

Bottom line: Your program 'starts' at onCreate() through onResume() but the OS is running the loop. Your program provides callbacks to the OS to handle whatever the OS sends to it. If you put a long loop at any point in your program it will appear to freeze because the OS (specifically the UI thread) is unable to get a slice of time. Use a thread for long loops.

Where is the main app class in an Android kotlin project?

You have to create a new App class like this:

class App : LocaleAwareApp() {
}

and in AndroidManifest add this line inside the application tag:

android:name=".App"

After that you create a BaseActivityClass:

open class BaseActivity : LocaleAwareCompatActivity() {  
}

and your MainActivity and every other activity you create should inherit from this BaseActivity like this:

class MainActivity: BaseActivity() {
}

For more customization you should look into https://github.com/zeugma-solutions/locale-helper-android

When/Where is Flutter's main() method called from the Android and iOS side of things?

On iOS

A main.m file was autogenerated in your Flutter projects ios/Runner directory, which defines the regular, main function which a C program implements, int main(int argc, char* argv[]);.

One compiled output can only have one main method, which the compiler will run immediately when the program is started. The following code creates a UIApplicationMain, which "Creates the application object and the application delegate and sets up the event cycle":

#import "AppDelegate.h"

int main(int argc, char* argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

It's simpler in Swift, just annotate AppDelegate with @UIApplicationMain.

The AppDelegate is the class which launches Flutter, because it extends FlutterAppDelegate. When FlutterAppDelegate is instantiated, iOS will create the FlutterViewController, which creates a FlutterEngine. It creates FlutterViewController because the FlutterViewController is configured in the Main.storyboard, which has been specified in the applications Info.plist. So technically, Flutter apps are Storyboard apps .

Screenshot of Xcode's Interface Builder with Main.storyboard open, with the identity inspector open showing the FlutterViewController as custom class.

Anyway, when the storyboard is created by iOS, the window property is set on the AppDelegate. You can get the FlutterViewController in the AppDelegate using window.rootViewController. An Objective-C++ file, FlutterViewController.mm's sharedSetupWithProject method creates a FlutterEngine using [[FlutterEngine alloc]initWithName:...:

- (void)sharedSetupWithProject:(nullable FlutterDartProject*)project
initialRoute:(nullable NSString*)initialRoute {
// Need the project to get settings for the view. Initializing it here means
// the Engine class won't initialize it later.
if (!project) {
project = [[[FlutterDartProject alloc] init] autorelease];
}
FlutterView.forceSoftwareRendering = project.settings.enable_software_rendering;
auto engine = fml::scoped_nsobject<FlutterEngine>{[[FlutterEngine alloc]
initWithName:@"io.flutter"
project:project
allowHeadlessExecution:self.engineAllowHeadlessExecution
restorationEnabled:[self restorationIdentifier] != nil]};

if (!engine) {
return;
}

_viewOpaque = YES;
_weakFactory = std::make_unique<fml::WeakPtrFactory<FlutterViewController>>(self);
_engine = std::move(engine);
_flutterView.reset([[FlutterView alloc] initWithDelegate:_engine opaque:self.isViewOpaque]);
[_engine.get() createShell:nil libraryURI:nil initialRoute:initialRoute];
_engineNeedsLaunch = YES;
_ongoingTouches.reset([[NSMutableSet alloc] init]);
[self loadDefaultSplashScreenView];
[self performCommonViewControllerInitialization];
}

Eventually, in FlutterEngine.mm, launchEngine is called, with the entrypoint (your dart's main function.)

- (void)launchEngine:(NSString*)entrypoint libraryURI:(NSString*)libraryOrNil {
// Launch the Dart application with the inferred run configuration.
self.shell.RunEngine([_dartProject.get() runConfigurationForEntrypoint:entrypoint
libraryOrNil:libraryOrNil]);
}

Shell::RunEngine is a C++ function implemented in shell.cc. I'm going to stop there for now. This is probably where the event loop starts , using platform_runner->PostTask(...).



On Android

In a generated Flutter project's android directory, MainActivity is declared in the AndroidManifest.xml to be the application which launches from the home screen.

When the activity is launched, Android will call the activity's onCreate method. Because MainActivity extends FlutterActivity, this onCreate method is called. FlutterActivityAndFragmentDelegate is instantiated, and its onAttach method is called. Eventually, a Java representation of FlutterEngine is created using:

    flutterEngine =
new FlutterEngine(
host.getContext(),
host.getFlutterShellArgs().toArray(),
/*automaticallyRegisterPlugins=*/ false,
/*willProvideRestorationData=*/ host.shouldRestoreAndSaveState());

This communicates with the C++ FlutterEngine library using FlutterJNI.

/**
* Interface between Flutter embedding's Java code and Flutter engine's C/C++ code.
*
* <p>Flutter's engine is built with C/C++. The Android Flutter embedding is responsible for
* coordinating Android OS events and app user interactions with the C/C++ engine. Such coordination
* requires messaging from an Android app in Java code to the C/C++ engine code. This communication
* requires a JNI (Java Native Interface) API to cross the Java/native boundary.
*

Later, in FlutterActivityAndFragmentDelegate, doInitialFlutterViewRun is called, which creates a DartEntryPoint, your main method again, based on the FlutterActivity's ActivityInfo. This gets the entrpoint function name using the following, but it will default to "main":

  @NonNull
public String getDartEntrypointFunctionName() {
try {
Bundle metaData = getMetaData();
String desiredDartEntrypoint =
metaData != null ? metaData.getString(DART_ENTRYPOINT_META_DATA_KEY) : null;
return desiredDartEntrypoint != null ? desiredDartEntrypoint : DEFAULT_DART_ENTRYPOINT;
} catch (PackageManager.NameNotFoundException e) {
return DEFAULT_DART_ENTRYPOINT;
}
}

Then, flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint); is called. So your main method has "been called". But this uses the FlutterJNI and the FlutterEngine C++ code. First, flutterJNI.runBundleAndSnapshotFromLibrary is called, and finally this JNI native method:

  private native void nativeRunBundleAndSnapshotFromLibrary(
long nativeShellHolderId,
@NonNull String bundlePath,
@Nullable String entrypointFunctionName,
@Nullable String pathToEntrypointFunction,
@NonNull AssetManager manager);

This native method is defined in platform_view_adroid_jni_impl.cc:

      {
.name = "nativeRunBundleAndSnapshotFromLibrary",
.signature = "(JLjava/lang/String;Ljava/lang/String;"
"Ljava/lang/String;Landroid/content/res/AssetManager;)V",
.fnPtr = reinterpret_cast<void*>(&RunBundleAndSnapshotFromLibrary),
},

Where RunBundleAndSnapshotFromLibrary is a C++ method:

static void RunBundleAndSnapshotFromLibrary(JNIEnv* env,
jobject jcaller,
jlong shell_holder,
jstring jBundlePath,
jstring jEntrypoint,
jstring jLibraryUrl,
jobject jAssetManager) {
auto asset_manager = std::make_shared<flutter::AssetManager>();

asset_manager->PushBack(std::make_unique<flutter::APKAssetProvider>(
env, // jni environment
jAssetManager, // asset manager
fml::jni::JavaStringToString(env, jBundlePath)) // apk asset dir
);

auto entrypoint = fml::jni::JavaStringToString(env, jEntrypoint);
auto libraryUrl = fml::jni::JavaStringToString(env, jLibraryUrl);

ANDROID_SHELL_HOLDER->Launch(asset_manager, entrypoint, libraryUrl);
}

Where AndroidShellHolder::Launch is:

void AndroidShellHolder::Launch(std::shared_ptr<AssetManager> asset_manager,
const std::string& entrypoint,
const std::string& libraryUrl) {
if (!IsValid()) {
return;
}

asset_manager_ = asset_manager;
auto config = BuildRunConfiguration(asset_manager, entrypoint, libraryUrl);
if (!config) {
return;
}
shell_->RunEngine(std::move(config.value()));
}

Just like iOS, Shell::RunEngine is called.

How to run the main method of an Android Activity class?

There is another option for the problem at hand, if the private method - which should be examined through the execution of a main method - can be extracted to another class. This of course means that the method suddenly became at least protected.

But if the method is definded within a class that does not derive from android.app.Activity a main method can be defined. You only have to adjust the Run Configuration in Eclipse.

  1. Run the class with Run as Java Application. This generates a new Run Configuration named like the class
  2. Edit the newly creaded Run Configuration
  3. Delete the Android library from Bootstrap Entries in the Classpath tab
  4. Add JRE 6 or so to the build path of the project
  5. Add this JRE to the Bootstrap Entries in the Classpath tab
  6. Add android.jar, which resides in the platforms directory of the Android SDK in User Entries in the Classpath tab


Related Topics



Leave a reply



Submit