Airo Global Software

Think Beyond Future !

Flutter

Flutter is Google’s portable UI tool for crafting beautiful, natively combined applications for mobile, web, and desktop from a single base code.

What Is Augmented Reality In Flutter?

- Posted in Flutter by

AR core in flutter is a wonderful plugin that gives us an API to perform Augmented presence in flutter applications. This is one of the emerging new technologies in the business. With this plugin, we shall consider the different features presented by this plugin the flutter, so let’s start.

How to Enable ARCore?

To qualify ARCore functionality in Android Studio you require to complete the following steps:-

  1. Include AR Required or AR Optional entries to the manifestAR

    Required

You need to include the below entries in your AndroidManifest.xml file:-

< uses-permission android:name="android.permission.CAMERA"  />
< uses-sdk android:minSdkVersion="24" />
< uses-feature android:name="android.hardware.camera.ar" />
< application …>
   < meta-data android:name="com.google.ar.core" android:value="required" />

AR Optional
< uses-permission android:name="android.permission.CAMERA" />
< uses-sdk android:minSdkVersion="14" />
< application>
   < meta-data android:name="com.google.ar.core" android:value="optional" />
< /application>

The difference between the AR Optional and AR Required is that AR Required app requires an ARCore Supported Devices that had Google Play Services for AR-enabled in it. In AR Required apps the play store automatically stores the Google Play Services for AR.

While in AR Optional apps can be installed and run on the machines that don’t support ARCore and also play store will not enable the Google Play Services for AR automatically.

  1. Modify build.gradle

Please ensure that your project's build.gradle file includes the below code.

allprojects {
   repositories {
       google()

Add the below dependencies in your app-level build.gradle file

dependencies {
 implementation 'com.google.ar:core:1.16.0'
}
  1. Sceneform plugin in your app-level build.gradle file
android {
   compileOptions {
       sourceCompatibility 1.8
       targetCompatibility 1.8
}
dependencies {
   implementation 'com.google.ar.sceneform.ux:sceneform-ux:1.8.0'
   implementation 'com.google.ar.sceneform:core:1.8.0'
}
  1. Enable android X

Include the below code into your gradle.properties

org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true

Which are the Classes provided by the plugin?

There are a total of 13 classes provided by this plugin.

  • ArCoreView
  • ArCoreController
  • ArCoreFaceView
  • ArCoreFaceContrller
  • ArCoreSphere
  • ArCoreCylinder
  • ArCoreCube
  • ArCoreNode
  • ArCoreMaterial
  • ArCoreHitTestResult
  • ArCoreRotatingNode
  • ArCorePlane
  • ArCoreReferenceNode

ArCoreView

This class returns the view kinds. There are two kinds of views in it.

  • AUGMENTEDFACE
  • STANDARDVIEW

There are 4 properties in it:-

  • onArCoreViewCreated
  • enableTapRecoginzer
  • enableUpdateListener
  • type

onArCoreViewCreated

This kind takes an ArCoreController. We shall discuss ArCoreController in our later section.

enableTapRecoginzer

Initially, set to false. It is made an augment by MethodChannel.

enableUpdateListener

Initially, set to false. It is used as an augment by the MethodChannel.

type

It is a view type, it is AUGMENTEDFACE, STANDARDVIEW. It is set to STANDARDVIEW by automatic.

ArCoreController

This controller used to add a ArNode using addArCoreNode function, include a ArCoreNode with anchor using a addArCoreNodeWithAncher function and also remove node using removeNode function.

ArCoreFaceView

It is a stateful widget that makes an ArCoreAndroidView. It has two characters: enableAugmentedFaces, onArCoreViewCreated.

At first, enableAugmentedFaces is set to false.

onArCoreViewCreated takes a program with an ArCoreController augment.

ArCoreFaceController

It is used to dispose of and loadMesh the method to control the FaceView.

ArCoreSphere

It is ArCoreShape, which takes a radius and ArCoreMaterial.

ArCoreCylender

It is ArCoreShape, which takes a radius, height, and ArCoreMaterial.

ArCoreCube

It is ArCoreShape, takes a size i.e. Vector3 and ArCoreMaterial.

ArCoreNode

This widget is used to give the position, shape, scale, rotation, name.

ArCoreMaterial

It is used to make the outlook of the virtual type generated by the user.

It has colour, texture bytes, metallic, roughness, reflection.

ArCoreRotatingNode

It is an ArCoreNode with a degree per second property which is a double value.

ArCorePlane

It takes the x, y of the plane, ArCorePose, and ArCorePlaneType.

There are three kinds of plane:-

  • HORIZONTAL_UPWARD_FACING
  • HORIZONTAL_DOWNWARD_FACING
  • VERTICAL

ArCoreReferenceNode

It is ArCoreNode, it has all the characteristics that the ArCoreNode has also it has objectUrl and object3DFileName.

objectUrl

URL of glft object for remote rendering.

object3DFileName

Filename of sfb object in assets folder. Making a Sphere

void _addSphere(ArCoreController controller) {
 final material = ArCoreMaterial(
   color: Color.fromARGB(120, 66, 134, 244),
 );
 final sphere = ArCoreSphere(
   materials: [material],
   radius: 0.1,
 );
 final node = ArCoreNode(
   shape: sphere,
   position: vector.Vector3(0, 0, -1.5),
 );
 controller.addArCoreNode(node);
}

Making a Cylinder

void _addCylinder(ArCoreController controller) {
 final material = ArCoreMaterial(
   color: Colors.red,
   reflectance: 1.0,
 );
 final cylinder = ArCoreCylinder(
   materials: [material],
   radius: 0.5,
   height: 0.3,
 );
 final node = ArCoreNode(
   shape: cylinder,
   position: vector.Vector3(0.0, -0.5, -2.0),
 );
 controller.addArCoreNode(node);
}

Making a Cube

void _addCube(ArCoreController controller) {
 final material = ArCoreMaterial(
   color: Color.fromARGB(120, 66, 134, 244),
   metallic: 1.0,
 );
 final cube = ArCoreCube(
   materials: [material],
   size: vector.Vector3(0.5, 0.5, 0.5),
 );
 final node = ArCoreNode(
   shape: cube,
   position: vector.Vector3(-0.5, 0.5, -3.5),
 );

 controller.addArCoreNode(node);
}

main.dart file

import 'package:arcore_flutter_plugin/arcore_flutter_plugin.dart';
import 'package:flutter/material.dart';
import 'package:vector_math/vector_math_64.dart' as vector;
void main() {
 runApp(HelloWorld());
}
class HelloWorld extends StatefulWidget {
 @override
 _HelloWorldState createState() => _HelloWorldState();
}
class _HelloWorldState extends State {
 ArCoreController arCoreController = ArCoreController();
 @override
 Widget build(BuildContext context) {
   return MaterialApp(
     home: Scaffold(
       appBar: AppBar(
         title: const Text('Hello World'),
       ),
       body: ArCoreView(
         onArCoreViewCreated: _onArCoreViewCreated,

       ),
     ),
   );
 }
 void _onArCoreViewCreated(ArCoreController controller) {
   arCoreController = controller;
   _addSphere(arCoreController);
   _addCylinder(arCoreController);
   _addCube(arCoreController);
 }
 void _addSphere(ArCoreController controller) {
   final material = ArCoreMaterial(
     color: Color.fromARGB(120, 66, 134, 244),
   );
   final sphere = ArCoreSphere(
     materials: [material],
     radius: 0.1,
   );
   final node = ArCoreNode(
     shape: sphere,
     position: vector.Vector3(0, 0, -1.5),
   );
   controller.addArCoreNode(node);
 }
 void _addCylinder(ArCoreController controller) {
   final material = ArCoreMaterial(
     color: Colors.red,
     reflectance: 1.0,
   );
   final cylinder = ArCoreCylinder(
     materials: [material],
     radius: 0.5,
     height: 0.3,
   );
   final node = ArCoreNode(
     shape: cylinder,
     position: vector.Vector3(0.0, -0.5, -2.0),
   );
   controller.addArCoreNode(node);
 }
 void _addCube(ArCoreController controller) {
   final material = ArCoreMaterial(
     color: Color.fromARGB(120, 66, 134, 244),
     metallic: 1.0,
   );
   final cube = ArCoreCube(
     materials: [material],
     size: vector.Vector3(0.5, 0.5, 0.5),
   );
   final node = ArCoreNode(
     shape: cube,
     position: vector.Vector3(-0.5, 0.5, -3.5),
   );
   controller.addArCoreNode(node);
 }
 @override
 void dispose() {
   arCoreController.dispose();
   super.dispose();
 }
}

If you have any doubt about this augment reality in flutters. If you want any software consultations and services, Don’t hesitate to contact us through the given email. Airo global software will always be your digital partner.

E-mail id: [email protected]

enter image description here Author - Johnson Augustine
Chief Technical Director and Programmer
Founder: Airo Global Software Inc
LinkedIn Profile: www.linkedin.com/in/johnsontaugustine/

How Geofencing define the Dart API?

Before signing any platform-specific code, I’ll first want to determine the Dart API for the geofencing plugin. Since Android and ios, several have their own APIs for designating and managing geofencing events, I want the Dart interface to present a reduced geofencing abstraction that is harmonious with both programs. Without going into too much detail about Android and iOS APIs, the following approximately represents the Dart interface that I’ll use for my plugin:

abstract class GeofenceRegion {
 /// The ID associated with the geofence.
 ///
 /// This ID identifies the geofence and is required to delete a
 /// specific geofence.
 final String id;

 /// The location (center point) of the geofence.
 final Location location;

 /// The radius around `location` that is part of the geofence.
 final double radius;

 /// Listen to these geofence events.
 final List triggers;

 /// Android-specific settings for a geofence.
 final AndroidGeofencingSettings androidSettings;

 GeofenceRegion(
   this.id, double latitude, double longitude, this.radius, this.triggers,
   {AndroidGeofencingSettings androidSettings});
}

abstract class GeofencingPlugin {
 /// Initialize the plugin and request relevant permissions from the user.
 static Future initialize() async;

 /// Register for geofence events for a [GeofenceRegion].
 ///
 /// `region` is the geofence region to register with the system.
 /// `callback` is the method to be called when a geofence event associated
 /// with `region` occurs.
 static Future registerGeofence(
   GeofenceRegion region,
   void Function(List id, Location location, GeofenceEvent event) callback);

 /// Stop receiving geofence events for a given [GeofenceRegion].
 static Future removeGeofence(GeofenceRegion region);


 /// Stop receiving geofence events for an identifier associated with a
 /// geofence region.
 static Future removeGeofenceById(String id) async;
}

This interface provides the below programmers to users of the plugin: The ability to create instances of GeofenceRegion, which include the emerges and radius of a geofence, a unique ID, and a collection of geofencing programmers to listen for. Since Android gives a richer set of lists for explaining geofences than iOS, Android-specific opportunities are made getting through the chosen androidSettings property. GeofencingPlugin.registerGeofence makes for the registration of a GeofenceRegion instance with a callback that is involved when a geofence event for that area is got. GeofencingPlugin.removeGeofence and GeofencingPlugin.removeGeofenceById will not a GeofenceRegion from triggering more events. Overall, this mode is rather simple and action-agnostic, making the plugin simple to act on both Android and iOS. Dart surronding execution This segment covers how to set up your isolate for experience execution. You will discover how to reference callbacks, and how to use the callback dispatcher. Referencing Callbacks Now that the Dart interface is defined, start figuring plumbing to communicate with the platform-particular divisions of the plugin. For example, the following program initializes the geofencing plugin and displays the geofences:

abstract class GeofencingPlugin {

 static const MethodChannel _channel =

     const MethodChannel('plugins.flutter.io/geofencing_plugin');

 static Future initialize() async {


   final callback = PluginUtilities.getCallbackHandle(callbackDispatcher);


   await _channel.invokeMethod('GeofencingPlugin.initializeService',


       [callback.toRawHandle()]);


 }

 static Future registerGeofence(


     GeofenceRegion region,


     void Function(List id, Location location, GeofenceEvent event)


         callback) {


   if (Platform.isIOS &&


       region.triggers.contains(GeofenceEvent.dwell) &&


       (region.triggers.length == 1)) {


     throw UnsupportedError("iOS does not support 'GeofenceEvent.dwell'");


   }


   final args = [


     PluginUtilities.getCallbackHandle(callback).toRawHandle()


   ];


   args.addAll(region._toArgs());
   _channel.invokeMethod('GeofencingPlugin.registerGeofence', args);


 }

 /*


 * … `removeGeofence` methods here …


 */


}

If you’ve previously created Flutter plugins and are common with MethodChannel, this should look is wanted, for the most part. However, the two calls to PluginUtilities.getCallbackHandle might outstanding. In order to provoke a Dart callback as a result of a surrounding event, you must take a handle that is passed among Dart and platform code while also keeping for lookup of the callback across platform threads and Dart. Retrieving a CallbackHandle for a method from PluginUtilities.getCallbackHandle has the bad effect of multiplying a callback cache within the Flutter engine. These cache maps details needed to wanted callbacks to raw integer handles, which are easy hashes added aimed at the properties of the callback. This cache persists across publishes, but be know that callback lookups may lose if the callback is renamed or moved and PluginUtilities.getCallbackHandle is not called for the updated version of callback. In the code that given, two instances of CallbackHandle are accessed one for the callback, which is assisted with a GeofenceRegion, and another for an option of the name callbackDispatcher. The callbackDispatcher method, the entry point of the background loneliness, is the reason for preprocessing raw geofence event data, seeing up callbacks via PluginUtilities.getCallbackFromHandle, and invoking them for registered geofences. The Callback Dispatcher As told at the end of the previous section, This pattern access for acting the initialization needed to establish connection channels with acting code while also allowing for the formation of non-trivial interfaces for callback options. For this geofencing plugin, the callback dispatcher planning is as follows:

void callbackDispatcher() {

 const MethodChannel _backgroundChannel =
    MethodChannel('plugins.flutter.io/geofencing_plugin_background');

 WidgetsFlutterBinding.ensureInitialized();

 _backgroundChannel.setMethodCallHandler((MethodCall call) async {


   final args = call.arguments;


   final Function callback = PluginUtilities.getCallbackFromHandle(


       CallbackHandle.fromRawHandle(args[0]));


   assert(callback != null);

   // 3.2. Preprocess arguments.

   final triggeringGeofences = args[1].cast();

   final locationList = args[2].cast();

   final triggeringLocation = locationFromList(locationList);


   final GeofenceEvent event = intToGeofenceEvent(args[3]);

   callback(triggeringGeofences, triggeringLocation, event);

 });
 _backgroundChannel.invokeMethod('GeofencingService.initialized');


}

As you can see, on the formation of callbackDispatcher only four methods are performed. a MethodChannel is made for listening to options from the plugin. Next, WidgetsFlutterBinding.ensureInitialized() is known to initialize the state required to connect with the Flutter engine. At this point, the MethodCall handler is set to work with plugin programmers before at last notifying the action portion of the plugin that the background makes it is mentioned and starting the handling events. Once the plugin is created transform programmers to the callback dispatcher, the callback given to the plugin user can be invoked. First, PluginUtilities.getCallbackFromHandle is known to take a moment of the callback assisted with the provoked geofencing program using the raw callback to hold. Next, the raw materials from the MethodCall are made into: A moment of List for the IDs of the geofences that were provoked. The moment that Location describes the current area of the machine An instance of the GeofenceEvent enum represents whether the machine has typed, exited, or dwelled within the provoked geofences. Then give this info as rules to our callback.

Background execution: Android For the Android installation of the plugin, I’ll be required to make the following sections: The GeofencingPlugin class, which is created with the Flutter engine in order to get and handle method calls built from Dart code A GeofencingBroadcastReceiver, which is provoked by the system on a geofence event The GeofencingService, which made the background isolate, merges the callback dispatcher defined earlier and processes geofence programmes invoking the callback dispatcher. Creating Geofences In order to influence options, select an instance of MethodChannel on the same channel from the past, and then register the GeofencingPlugin instance with this channel in the implementation of onAttachedToEngine:

override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {

 mContext = binding.getApplicationContext()

 mGeofencingClient = LocationServices.getGeofencingClient(mContext!!)


 val channel = MethodChannel(binding.getBinaryMessenger(), "plugins.flutter.io/geofencing_plugin")


 channel.setMethodCallHandler(this)


}

In order to manage these needs, onMethodCall is required to install:

override fun onMethodCall(call: MethodCall, result: Result) {




 val args = call.arguments>()


 when(call.method) {


   "GeofencingPlugin.initializeService" -> {


     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {


       mActivity?.requestPermissions(REQUIRED_PERMISSIONS, 12312)


     }


     // Simply stores the callback handle for the callback dispatcher


     initializeService(mContext!!, args)


     result.success(true)


   }


   "GeofencingPlugin.registerGeofence" -> registerGeofence(mContext!!,


           mGeofencingClient!!,


           args,


           result,


           true)


   "GeofencingPlugin.removeGeofence" -> removeGeofence(mContext!!,


           mGeofencingClient!!,


           args,


           result)


   else -> result.notImplemented()


 }


}

At last, include the skill to register geofences

@JvmStatic

private fun getGeofencingRequest(geofence: Geofence, initialTrigger: Int): GeofencingRequest {


 return GeofencingRequest.Builder().apply {


   setInitialTrigger(initialTrigger)


   addGeofence(geofence)


 }.build()

}
@JvmStatic


private fun getGeofencePendingIndent(context: Context, callbackHandle: Long): PendingIntent {


val intent = Intent(context, GeofencingBroadcastReceiver::class.java)


       .putExtra(CALLBACK_HANDLE_KEY, callbackHandle)


return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)


}

// TODO(bkonyi): Reregister geofences after reboot


// https://developer.android.com/training/location/geofencing


@JvmStatic


private fun registerGeofence(context: Context,


                             geofencingClient: GeofencingClient,


                             args: ArrayList<*>?,


                             result: Result?) {


 val callbackHandle = args!![0] as Long


 val id = args[1] as String


 val lat = args[2] as Double


 val long = args[3] as Double


 val radius = (args[4] as Number).toFloat()


 val fenceTriggers = args[5] as Int


 val initialTriggers = args[6] as Int


 val expirationDuration = (args[7] as Int).toLong()


 val loiteringDelay = args[8] as Int


 val notificationResponsiveness = args[9] as Int


 val geofence = Geofence.Builder()


         .setRequestId(id)


         .setCircularRegion(lat, long, radius)

         .setTransitionTypes(fenceTriggers)

         .setLoiteringDelay(loiteringDelay)
         .setNotificationResponsiveness(notificationResponsiveness)
         .setExpirationDuration(expirationDuration)
         .build()
 // Ensure permissions are set properly.

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
        (context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)

                 == PackageManager.PERMISSION_DENIED)) {
   val msg = "'registerGeofence' requires the ACCESS_FINE_LOCATION permission."
   Log.w(TAG, msg)
   result?.error(msg, null, null)

 }
 ofencingClient.addGeofences(getGeofencingRequest(geofence, initialTriggers),

         getGeofencePendingIndent(context, callbackHandle))?.run {

   addOnSuccessListener {
     Log.i(TAG, "Successfully added geofence")
     result?.success(true)
   }
   addOnFailureListener {
     Log.e(TAG, "Failed to add geofence: $it")
     result?.error(it.toString(), null, null)
   }
 }
}

Scheduling the geofencing service:

class GeofencingBroadcastReceiver : BroadcastReceiver() {
 companion object {
   private const val TAG = "GeofencingBroadcastReceiver"
 }
 override fun onReceive(context: Context, intent: Intent) {
   FlutterMain.startInitialization(context)
   FlutterMain.ensureInitializationComplete(context, null)
   GeofencingService.enqueueWork(context, intent)
 }
}

Handling Geofence Events using the below code:

private fun startGeofencingService(context: Context) {
 synchronized(sServiceStarted) {
   mContext = context
   // dispatcher.
   if (sBackgroundFlutterEngine == null) {
     val callbackHandle = context.getSharedPreferences(

        GeofencingPlugin.SHARED_PREFERENCES_KEY,

         Context.MODE_PRIVATE)
         .getLong(GeofencingPlugin.CALLBACK_DISPATCHER_HANDLE_KEY, 0)

     if (callbackHandle == 0L) {

       Log.e(TAG, "Fatal: no callback registered")
       return
     }
     val callbackInfo = FlutterCallbackInformation.lookupCallbackInformation(callbackHandle)

     if (callbackInfo == null) {

       Log.e(TAG, "Fatal: failed to find callback")

       return

     }

     sBackgroundFlutterEngine = FlutterEngine(context)

     val args = DartCallback(

       context.getAssets(),

       FlutterMain.findAppBundlePath(context)!!,

       callbackInfo

     )
     sBackgroundFlutterEngine!!.getDartExecutor().executeDartCallback(args)

   }

 }
 mBackgroundChannel = MethodChannel(sBackgroundFlutterEngine!!.getDartExecutor().getBinaryMessenger(),

     "plugins.flutter.io/geofencing_plugin_background")

 mBackgroundChannel.setMethodCallHandler(this)

}

After startGeofencingService is completed execution, onHandleWork is called by the machine with the Intent that was lined up earlier:

 val locationList = listOf(location.latitu
override fun onHandleWork(intent: Intent) {

 val callbackHandle = intent.
   getLongExtra(GeofencingPlugin.CALLBACK_HANDLE_KEY, 0)
 val geofencingEvent = GeofencingEvent.fromIntent(intent)
 if (geofencingEvent.hasError()) {
   Log.e(TAG, "Geofencing error: ${geofencingEvent.errorCode}")

   return
 }
 val geofenceTransition = geofencingEvent.geofenceTransition
 val triggeringGeofences = geofencingEvent.triggeringGeofences.map {
   it.requestId
 }

 val location = geofencingEvent.triggeringLocation

de,
   location.longitude)
 val geofenceUpdateList = listOf(callbackHandle,
   triggeringGeofences,
   locationList,
   geofenceTransition)
  
 synchronized(sServiceStarted) {
   if (!sServiceStarted.get()) {
    
     queue.add(geofenceUpdateList)
   } else {
     
     mBackgroundChannel.invokeMethod("", geofenceUpdateList)
   }
 }
}

You have to write the below code next:

override fun onMethodCall(call: MethodCall, result: Result) {

 if (call.method == "GeofencingService.initialized") {

   synchronized(sServiceStarted) {

     while (!queue.isEmpty()) {

       mBackgroundChannel.invokeMethod("", queue.remove())

     }

     sServiceStarted.set(true)

     result.success(null)

   }

 } else {

   result.notImplemented()
 }
}

At this point, the GeofencingService is fully initialized and any geofencing events that have lined up are sent to the callback dispatcher. Background execution: iOS Now that the geofencing plugin implementation for Android is completed, the same geofencing program is required to be implemented for iOS. Initializing the plugin using the below code

+ (void)registerWithRegistrar:(NSObject *)registrar {

 @synchronized(self) {

   if (instance == nil) {

     NSLog(@"Registering with registrar");

     instance = [[GeofencingPlugin alloc] init:registrar];

     [registrar addApplicationDelegate:instance];

   }

 }

}

Additional state for the plugin is created when the GeofencingPlugin instance is build during plugin registration:

- (instancetype)init:(NSObject *)registrar {

 self = [super init];

 NSAssert(self, @"super init cannot be nil");

 _persistentState = [NSUserDefaults standardUserDefaults];

 _locationManager = [[CLLocationManager alloc] init];

 [_locationManager setDelegate:self];

 [_locationManager requestAlwaysAuthorization];

 _locationManager.accessBackgroundLocationUpdates = YES;

 _headlessRunner = [[FlutterEngine alloc]

                       initWithName:@"GeofencingIsolate"

                       project:nil

                       allowHeadlessExecution:YES];


 _registrar = registrar;

 _mainChannel = [FlutterMethodChannel
                 methodChannelWithName:@"plugins.flutter.io/geofencing_plugin"


                 binaryMessenger:[registrar messenger]];

 [registrar addMethodCallDelegate:self channel:_mainChannel];
 _callbackChannel =
   [FlutterMethodChannel methodChannelWithName:@"plugins.flutter.io/geofencing_plugin_background"

     binaryMessenger:_headlessRunner];
 return self;

}

Starting the callback dispatcher:

- (void)startGeofencingService:(int64_t)handle {

 NSLog(@"Initializing GeofencingService");


 [self setCallbackDispatcherHandle:handle];

 FlutterCallbackInformation *info = [FlutterCallbackCache lookupCallbackInformation:handle];


 NSAssert(info != nil, @"failed to find callback");

 NSString *entrypoint = info.callbackName;

 NSString *uri = info.callbackLibraryPath;
 [_headlessRunner runWithEntrypointAndLibraryUri:entrypoint libraryUri:uri];
 NSAssert(registerPlugins != nil, @"failed to set registerPlugins");
 registerPlugins(_headlessRunner);
 [_registrar addMethodCallDelegate:self channel:_callbackChannel];
}

Handling method calls:

- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
 NSArray *arguments = call.arguments;
 if ([@"GeofencingPlugin.initializeService" isEqualToString:call.method]) {
   NSAssert(arguments.count == 1,
   @"Invalid argument count for 'GeofencingPlugin.initializeService'");
   [self startGeofencingService:[arguments[0] longValue]];
   result(@(YES));
 } else if ([@"GeofencingService.initialized" isEqualToString:call.method]) {
   // Ignored on iOS.
   result(nil);
 } else if ([@"GeofencingPlugin.registerGeofence" isEqualToString:call.method]) {
   [self registerGeofence:arguments];
   result(@(YES));
 } else if ([@"GeofencingPlugin.removeGeofence" isEqualToString:call.method]) {

   result(@([self removeGeofence:arguments]));
 } else {
   result(FlutterMethodNotImplemented);
 }
}

Registering geofences:

- (void)registerGeofence:(NSArray *)arguments {
 NSLog(@"RegisterGeofence: %@", arguments);
 int64_t callbackHandle = [arguments[0] longLongValue];
 NSString *identifier = arguments[1];
 double latitude = [arguments[2] doubleValue];
 double longitude = [arguments[3] doubleValue];
 double radius = [arguments[4] doubleValue];
 CLCircularRegion *region =
   [[CLCircularRegion alloc] initWithCenter:CLLocationCoordinate2DMake(latitude, longitude)
     radius:radius
     identifier:identifier];
 region.notifyOnEntry = YES;
 region.notifyOnExit = YES;
 [self setCallbackHandleForRegionId:callbackHandle regionId:identifier];
 [self->_locationManager startMonitoringForRegion:region];
}

For Handling geofence events use the below code:

- (void)sendLocationEvent:(CLRegion *)region eventType:(int)event {
 NSAssert([region isKindOfClass:[CLCircularRegion class]], @"region must be CLCircularRegion");
 CLLocationCoordinate2D center = region.center;
 int64_t handle = [self getCallbackHandleForRegionId:region.identifier];
 [_callbackChannel
   invokeMethod:@""
   arguments:@[
     @(handle),
     @[ region.identifier ],
     @[ @(center.latitude), @(center.longitude) ],
     @(event)
   ]
 ];
}
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
 [self sendLocationEvent:region eventType:kEnterEvent];
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
 [self sendLocationEvent:region eventType:kExitEvent];
}

For Geofence events in a suspended state below code:

- (BOOL)application:(UIApplication *)application
 didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

 // Check to see if we're being launched due to a location event.

 if (launchOptions[UIApplicationLaunchOptionsLocationKey] != nil) {

   // Restart the headless service.


   [self startGeofencingService:[self getCallbackDispatcherHandle]];
 }
 return YES;
}

To get Permissions: Android use the below code:





To get Permissions in iOS:

UIRequiredDeviceCapabilities

 

   location-services

   gps

   armv7

 

 UIBackgroundModes

 

   location

 

NSLocationAlwaysAndWhenInUseUsageDescription

 YOUR DESCRIPTION HERE

 NSLocationWhenInUseUsageDescription

 YOUR DESCRIPTION HERE

These descriptions are shown to the person who uses them when the app requests access to themarea.

#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"

// Add the import for the GeofencingPlugin.

#import 

void registerPlugins(NSObject* registry) {

 [GeneratedPluginRegistrant registerWithRegistry:registry];

}

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application

   didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

 // Register the plugins with the AppDelegate


 registerPlugins(self);

 // Set registerPlugins as a callback within GeofencingPlugin. This access

 // for the Geofencing plugin to register the plugins with the background

 // FlutterEngine instance created to handle events. If this step is skipped,

 // other plugins will not work in the geofencing callbacks!

 [GeofencingPlugin setPluginRegistrantCallback:registerPlugins];

 // Override point for customization after application launch.

 return [super application:application didFinishLaunchingWithOptions:launchOptions];

}

@end

Bringing it all together:

Future initialize() async {

 // Perform other initialization

 // …

 // Initialize the geofencing plugin.

 await GeofencingManager.initialize();

}

Widget _proximityTriggerToggle() => Container(

   padding: const EdgeInsets.fromLTRB(26.0, 2.5, 26.0, 2.5),

   child: Row(

     mainAxisAlignment: MainAxisAlignment.spaceBetween,

     children: [

       const Text('Proximity Trigger',

           style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0)),

       Switch(

         value: _proximityTriggerEnabled,

         onChanged: (bool state) async {

           setState(() {

             _proximityTriggerEnabled = state;

           });

           if (state) {

             await GeofencingManager.registerGeofence(

                 GeofenceTrigger.homeRegion,

                 GeofenceTrigger.homeGeofenceCallback);

           } else {

             await GeofencingManager.removeGeofence(

                 GeofenceTrigger.homeRegion);

           }

         },

       ),

     ],

   )

 );

abstract class GeofenceTrigger {

 static final _androidSettings = AndroidGeofencingSettings(

     initialTrigger: [GeofenceEvent.exit],

     notificationResponsiveness: 0,

     loiteringDelay: 0);

 static bool _isInitialized = false;

 static final homeRegion = GeofenceRegion(

     'home', HOME_LAT, HOME_LONG, 300.0, [GeofenceEvent.enter],

     androidSettings: _androidSettings);

 static Future homeGeofenceCallback(

     List id, Location location, GeofenceEvent event) async {

   // Check to see if this is the first time the callback is being called.

   if (!_isInitialized) {

     // Re-initialize state required to communicate with the garage door

     // server.

     await initialize();

     _isInitialized = true;

   }

   if (event == GeofenceEvent.enter) {

     await GarageDoorRemote.openDoor();

   }

 }

}

At last, you execute a dart in the background with flutter plugin and geofencing

If you have any questions about the above topic or have to get services and consultations to setup flutter and dart plugins. Feel free to contact us. AIRO GLOBAL SOFTWARE will be your digital solution. E-mail id: [email protected]

enter image description here Author - Johnson Augustine
Chief Technical Director and Programmer
ounder: Airo Global Software Inc
LinkedIn Profile: www.linkedin.com/in/johnsontaugustine/

enter image description here

One way or another we develop our apps to make cash out of it. Sometimes we sell ads and make users upgrade for a great experience and we have premium content only for paid users.

We should know about each and every piece of information before handling the payment-related stuff. Be prepared before you start to know about Subscriptions In-App Purchase in Flutter.

Before we get into the programming part let’s learn more about in-app purchases and how it is different for both Android and IOS platforms.

What are the types of products in Android and IOS?

There are types of products in both Android and IOS: First Know about the Products in Android:

  • Consumable product: Products like in-game currency are examples of this type of product. Once the user starts to use them, the user can purchase it again.
  • Non-Consumable product: These can be bought only once and it gives a permanent benefit.
  • Subscriptions: These give benefits to the user for a limited period. You can compare Netflix, Spotify subscriptions to these products.

Know about Products in iOS

  • Consumable product.

  • Non-Consumable product.

  • Auto-Renewable Subscriptions: same as android subscriptions.

  • Non-Renewing Subscriptions: It is almost the same as Auto-Renewable Subscriptions.

What are the steps to add a subscription in the Flutter app?

  • First step is we need to Create a Product

    How to create a product for Android:

  • First go to Google Play Console

  • Second step is to click the app for which you want to build a subscription.

  • Third step is to go Inside the menu under Monetize > Products click Subscriptions.

  • Fourth step is to fill the form with the needed details. Here product id is the most essential field. Product id is used to uniquely find each product.

How to create a product for iOS:

  • First you have to Go to App Store Connect.
  • Second step is to click the app for which you want to make a subscription.
  • Third step is to click In the side menu under the in-app purchase section and now click the manage option.
  • Fourth step is to press the plus sign to include new products and select the type of subscription you want.
  • Fifth step is to type the product name and product id. Here product id is the same as android.
  • Sixth step is to select a subscription group and make a new group.
  • Seventh step is to add a subscription group or make a new group.
  • The last step is to Fill every mandatory information. If any given information is missing for the product then the status of the product will be Missing Metadata. Fill every single information until the status changes to Ready to Submit.
  • Second step is to set up testing accounts.

How to setup testing account for Android:

  • Include the tester’s email address in the applications license testers.
  • Include the same used email address in the app’s tester list.

How to setup testing account for IOS:

  • First step is to go to the app store connect.
  • Second step is to go to User and Access.
  • Third step is to find the Tester option under Sandbox. Press on that.
  • Fourth step is to press on the plus sign to include an apple pay sandbox tester.

Need to understand how the purchase of subscription works:

  • The application notifies the billing server that the present user wants to buy a product with id.
  • The billing Server needs the purchase and gives back the response.
  • The response gets at the application through PurchaseUpdateStream.
  • Your application always checks the status of the purchase and takes the action accordingly.
  • If the purchase was correct the application will notify the application’s back end that this user has perfectly purchased a product and this is the shopping token I got from the billing server.
  • The application’s back end will check the purchase with the billing server before giving any advantages to the user. After perfect validation, your app’s back end will mark the present user as a premium user and notify the application.
  • Now the app has to finish the transaction with the billing server. Completion of the transaction is a way of ordering the billing server that you have perfectly delivered the product to the user.
  • Transaction that finished is different for Android and iOS. In Android, you just have to finish the transaction which is successful. In iOS, you have to finish every transaction irrespective of the status of the transaction.
  • Transaction completion is very important because if you don’t finish the transaction in Android, Google will give back the amount of purchase considering that the purchase was failed.
  • In case of application crashes or network problems happening during the transaction when the user opens the application again your app will be notified with all the unfinished transactions through the PurchaseUpdateStream. So, you can continue the plan of purchase of the product.
  • Based on the response received from the app’s back end you will show a special display to the user.

Next step is to integrate in-App purchases with flutter.

To manage our code we will develop one new folder:

class
PaymentService {
/// We want singleton object of ``PaymentService`` so 
create private constructor
 ///
/// Use PaymentService as ``PaymentService.instance``
PaymentService._internal();
static final PaymentService instance = 
PaymentService._internal();
}

Next is to create some variables:

class 
PaymentService
{
/// We want singleton object of ``PaymentService`` so create
private constructor
///
/// Use PaymentService as ``PaymentService.instance``
PaymentService._internal();
static final PaymentService instance =
PaymentService._internal();
/// To listen the status of connection between app and the billing server
StreamSubscription<ConnectionResult>
_connectionSubscription;
/// To listen the status of the purchase made inside or outside of the app (App Store / Play Store)
///
/// If status is not error then app will be notied by this stream
StreamSubscription<PurchasedItem>
_purchaseUpdatedSubscription;
/// To listen the errors of the purchase
StreamSubscription<PurchaseResult>
_purchaseErrorSubscription;
/// List of product ids you want to fetch
final List<String> _productIds = [
'monthly_subscription'
];

/// All available products will be store in this list List _products;

/// All past purchases will be store in this list
List<PurchasedItem> _pastPurchases;
/// view of the app will subscribe to this to get notified
/// when premium status of the user changes
ObserverList<Function> _proStatusChangedListeners =
new ObserverList<Function>();
/// view of the app will subscribe to this to get errors of the purchase
 ObserverList<Function(String)> _errorListeners =
 new ObserverList<Function(String)>();
/// logged in user's premium status
bool _isProUser = false;
bool get isProUser => _isProUser;
}

Want to get the UI latest updates use the below code:

 addToProStatusChangedListeners(Function callback) {
 _proStatusChangedListeners.add(callback);
}
/// view can cancel to _proStatusChangedListeners using this method

removeFromProStatusChangedListeners(Function callback) {

_proStatusChangedListeners.remove(callback);
 }
/// view can subscribe to _errorListeners using this method
addToErrorListeners(Function callback) {
_errorListeners.add(callback);
}
 /// view can cancel to _errorListeners using this method
removeFromErrorListeners(Function callback) {
_errorListeners.remove(callback);
 }

Following code to notify the user:

void _callProStatusChangedListeners() {
_proStatusChangedListeners.forEach((Function callback) {
 callback();
 });
}

 /// Call this method to notify all the subsctibers of _errorListeners
void _callErrorListeners(String error) {
 _errorListeners.forEach((Function callback) {
callback(error);
});
}

Call the interconnection method at the start your app using below code:

 /// with billing server and get all the necessary data
 void initConnection() async {
await FlutterInappPurchase.instance.initConnection;
 _connectionSubscription =
FlutterInappPurchase.connectionUpdated.listen((connected) {});
 _purchaseUpdatedSubscription =
FlutterInappPurchase.purchaseUpdated.listen(_handlePurchaseUpdate);
_purchaseErrorSubscription =
FlutterInappPurchase.purchaseError.listen(_handlePurchaseError);
_getItems();
 _getPastPurchases();
}
 /// call when user close the app
void dispose() {
_connectionSubscription.cancel();
 _purchaseErrorSubscription.cancel();
 _purchaseUpdatedSubscription.cancel();
FlutterInappPurchase.instance.endConnection;
}

Handle purchase errors using the below code:

void _handlePurchaseError(PurchaseResult
purchaseError) {
_callErrorListeners(purchaseError.
message);
}

For handle purchase updates:

void _handlePurchaseUpdate(PurchasedItem productItem) async
{
if (Platform.isAndroid) {
await _handlePurchaseUpdateAndroid(productItem);
 } else {
await _handlePurchaseUpdateIOS(productItem);
}
}

For finish the transaction:

Future<void> 
_handlePurchaseUpdateI
OS(PurchasedItem
purchasedItem) async {
switch (purchasedItem.transactionStateIOS) {
case TransactionState.deferred:
// Edit: This was a bug that was pointed out here : 
https://github.com/dooboolab/flutter_inapp_purchase/issues/234
//
FlutterInappPurchase.instance.finishTransaction(purchasedItem);
break;
case TransactionState.failed:
 _callErrorListeners("Transaction Failed");
FlutterInappPurchase.instance.finishTransaction(purchasedItem);
 break;
case TransactionState.purchased:
await
_verifyAndFinishTransaction(purchasedItem);
break;
case TransactionState.purchasing:
break;
 case TransactionState.restored:
FlutterInappPurchase.instance.finishTransaction(purchasedItem);
break;
default:
}
 }
/// three purchase state 
https://developer.android.com/reference/com/android/billingclient/api/Purchase.PurchaseState
/// 0 : UNSPECIFIED_STATE
/// 1 : PURCHASED
 /// 2 : PENDING
Future<void> 
_handlePurchaseUpdateAndroid(PurchasedItem purchasedItem) async {
switch (purchasedItem.purchaseStateAndroid) {
 case 1:
if (!purchasedItem.isAcknowledgedAndroid) {
 await 
_verifyAndFinishTransaction(purchasedItem);

}
  break;
default:
_callErrorListeners("Something went wrong");
 }
}

For verify purchase is success:

 /// Call API of your back end to verify the receipt
 /// back end has to call billing server's API to verify the purchase token
 _verifyAndFinishTransaction(PurchasedItem purchasedItem) async {
bool isValid = false;
try {
// Call API
isValid = await _verifyPurchase(purchasedItem);
} on NoInternetException {
_callErrorListeners("No Internet");
 return;
} on Exception {
 _callErrorListeners("Something went wrong");
return;
}
 if (isValid) {
 FlutterInappPurchase.instance.finishTransaction(purchasedItem);
 _isProUser = true;
// save in sharedPreference here
_callProStatusChangedListeners();
} else {
_callErrorListeners("Verification failed");
}
}

For get all the available products:

Future<List<IAPItem>> get
products async {
 if (_products == null) {
await _getItems();
}
}
return _products;
}
Future<void> _getItems() async {
List<IAPItem> items =
await 
FlutterInappPurchase.instance.getSubscriptions
(_productIds);
 _products = List();
 for (var item in items) {
this._products.add(item);
}
}

To buy the product:

Future<Null> 
buyProduct(IAPItem item)
async {
try {
await 
FlutterInappPurchase.instance.requestSubscription(item.productId);
 } catch (error) {
 }
}

If you have any doubts about the above topic or have to get services and consultations and get the best Flutter application services. Feel free to contact us. AIRO GLOBAL SOFTWARE will be your strong digital partner. E-mail id: [email protected]

enter image description here Author - Johnson Augustine
Chief Technical Director and Programmer
Founder: Airo Global Software Inc
LinkedIn Profile: www.linkedin.com/in/johnsontaugustine/

enter image description here

The floor provides a neat SQLite abstraction for your Flutter apps it is inspired by the Room persistence library. It comes with default mapping between memory objects and database rows while still giving complete control of the database with the use of SQL.

What is Flutter?

The Flutter framework contained both a software development kit and their widget-based user interface library. This library consists stained of various inoperable UserInterface elements, such as sliders and buttons.

Developers who create mobile applications with the Flutter framework will do so using a language called Dart. With a command like JavaScript, Dart is a typed programming language that completely focuses on front-end development.

You can save, query and, remove your Objects in a simple and direct way with the Floor database!

How do we start?

To start with Floor, let’s include these dependencies in pubspec.yaml

dependencies:
 flutter:
sdk: flutter
floor: ^0.14.0
dev_dependencies:
 floor_generator: ^0.14.0
build_runner: ^1.7.3

What about the entity class?

The entity class will always represent database table Columns. The @entity adds the class as a persistent class and you need to include a primaryKey.

// entity/student.dart
import 'package:floor/floor.dart';
@Entity(tableName: 'students')
class Student {
@primaryKey(autoGenerate: true)
final int id;
final String name;
final Float grade;
Person(this.id, this.name, this.grade);
}

What about data access objects?

This component is the most responsible for managing enable to the underlying SQLite database.

You can use the normal SQLite @Query or @insert, @delete and @update.

// dao/student_dao.dart
import 'package:floor/floor.dart';
@dao
abstract class StudentDao {
@Query('SELECT * FROM students')
Future<List<Student>> findAllStudents();
@Query('SELECT * FROM students WHERE id = :id')
Stream<Student> findStudentById(int id);
@insert
Future<void> insertStudent(Student student);
@Query('DELETE FROM students WHERE id = :id')
Future<void> delete(int id);
}

What about a Database?

It has to be an abstract class that will be extends FloorDatabase

// database.dart
// required package imports
import 'dart:async';
import 'package:floor/floor.dart';
import 'package:sqflite/sqflite.dart' as sqflite;
import 'dao/student_dao.dart';
import 'entity/student.dart';
part 'database.g.dart'; // the generated code will be there
@Database(version: 1, entities: [Student])
abstract class AppDatabase extends FloorDatabase {
StudentDao get studentDao;
}
part 'database.g.dart';

make sure to add the above line and it should be equal to your database file name which in our scene is atabase.dart.

How to Build the database?

After that, go to the terminal and execute

flutter packages pub run build_runner build

make sure that you added flutter to your surrounding variables. Now you can easily access your database using :

$Floor +

your database class name which in our scene is AppDatabase

final database = await
$FloorAppDatabase.databaseBuilder('app_database.db').build();
final studentDao = database.studentDao;
final student= Student(1, 'Frank', 99);
await studentDao.insertStudent(student);
final result = await personDao.findPersonById(1);

If you want to generate the Id by default, then you can easily pass null instead of Id in the entity object, i.e:

final student= Student(null, 'Frank', 99);
await studentDao.insertStudent(student);

I hope you enjoyed this nice and easy database.

If you have any doubts about the above topic or have to get services and consultations and get flutter app development company. Feel free to contact us. AIRO GLOBAL SOFTWARE will be your strong digital partner. E-mail id: [email protected]

enter image description here

Author - Johnson Augustine
Chief Technical Director and Programmer
Founder: Airo Global Software Inc
LinkedIn Profile: www.linkedin.com/in/johnsontaugustine/

enter image description here

If you have to make a flutter app and are ready to release it on the Apple Store, then you are in the perfect place. In this blog, you will learn the process of how to publish the flutter app on the Apple store. There are some efficient points that you should always remember before publishing the app to the Apple store. Do you know that Apple is very restrictive about user privacy and UI design?. Don’t worry about that, We are going to cover the common problems that a new developer does during the publishing of their first iOS app. If you want to build a flutter app with perfect user design visit a flutter app development company for great works.

What is flutter?

Flutter is a UI toolkit for building fast, beautiful, natively compiled applications for mobile, web, and desktop with one programing language and single codebase. Flutter is a cross-platform development framework that has the ability to write one code and can deploy on different platforms. Actually, it saves a lot of time and effort for developers.

What are the steps to release the flutter ios app on the apple store?

  • First, you have to create an Apple Developer Account
  • Then you should Register Bundle Identifier
  • Next, you have to Get App icon and App screenshot ready
  • Then the next step is app Store Connect Listing Process
  • The last and final step isOpen Project on Xcode and Build

How to create an app developer account?

First, you go to the apple developer account official registration website and build an Apple developer account. Do not forget that an Apple developer account is associated with your email ID. So, choose the correct email ID and keep it a secret. Apple developer accounts have an annual fee that you should have to pay.

Ok, when you are going to publish an app for your user. it is a good exercise to create a separate account for them to avoid problems in the future.

How to register a bundle identifier?

After you register for the developer account, the first most important thing you need to do is register a Bundle ID. Every iOS app is associated with a Bundle ID, which is a rare identifier registered with Apple.

  1. On the official Apple developer account select “Certificates Identifiers and Profiles”. On the left side, the menu selects “Identifiers”.
  2. Click “+” to create a Bundle ID. Select “App ID” on the next following page and select continue.
  3. Select App type and then select “App” and click continue.
  4. On the following page select “Register an App ID” – Add a short description and select Bundle ID as Explicit and type an “App Package Name”
  5. On the next following page, confirm the information given and select Register to register your Bundle ID.

How to create an app icon and screenshot?

Ok now you have a bundle ID, it’s time to start a flutter project to fulfill the Apple instructions. We need to build multiple app icons for different devices. There are various tools available to build iOS icons like app icon generators, Just put a 1024×1024 px image and it will give you all of the apple icons. Now, you can download the zip file and extract it. Next, you can found that a file named “AppIcon.appiconset” inside the “Assets. cassettes” folder. Copy this file and open the flutter project on your Android studio. Select the iOS file in the project directory called your_project_name/ios/Runner/Assets.cassettes/AppIcon.appiconset. Paste and change the copied folder in the given location.

You can change the screen by removing “LauncherImage” with “LaunchImage.images”. Apple has provided the instructions on its official page, Please take an effort to read it.

How to do the app store connect listing process?

Next, you have to go through the apple store connection and select "my App." Select on the “+” icon to create the App. On the pop-up window, write the App name, select language, select the Bundle ID that you made in the last step, and write SKU. Please click on the full access radio button and select “Create”.

Now, on the next following page fill in all of the information. Please be careful when putting the screenshot. Following are the screenshot image dimensions:

  • app screenshot 6.5 display – 1242×2688, 2688×1242, 1284x 2778
  • app screenshot 5.5 display – 1242x 2208, 2208x 1242
  • app screenshot 12.9 3rd. – 2048×2732, 2732x 2048
  • app screenshot 12.9 2nd. – 2048×2732, 2732x 2048

Please Don’t forget the screenshot images should not contain the “flutter debug” tag . You can remove the flutter debug tag by writing the below code in the app.

MaterialApp( debugShowCheckedModeBanner: false,)

How to open the project on Xcode and build?

O the time has arrived to publish the app on Apple Connect. Open flutter project in Android studio, and select tool/firebase/ open ios module on XCode. Your flutter project has been perfectly exported into XCode. The first test app is running correctly or not in Xcode. Connect your iPhone device by a USB cable, and select the “RUN” on the top of the XCode. If there are any mistakes when running Xcode, then close the window, and execute it on Android studio to make the correction in the code.

Once you run the code successfully, On the Xcode window, Navigate to your target’s on settings in Xcode:

  1. In the main sidebar, click the Runner target.
  2. Select the General tab. There, you can change the app name. Do not forget, the bundle identifier should be the same that you have built in the early stage.
  3. Look through the deployment info section, and click device.
  4. If you are using Xcode for the first time, then it will promote you to log in with your Developer ID. Just sign in and, then, click TEAM as your developer account. Then check to automatically manage sign-in.
  5. Rest forms are automatically filled for you; you don’t need to make any changes.
  6. Go to Product/Destination/Build.
  7. Go to Product/Archive. Now you will see a pop-up window. Select the validate app and keep continuing until you get a message that notifies you that it was successful.
  8. Once the app gets validated, select Distribute App and the same pop-up window will appear. Once you get to a correct release of the app on the apple store, that means your build is ready to publish.
  9. It will take 10-20 minutes to appear to build on the apple store connect.
  10. So you are ready to “Submit for review”. Select it; if you forgot any field to be filled then you will get the notification that will appear on top beside the “submit for review” button. Fill in all the details, and submit the app.

You will get an email notification whenever the review has been changed by the Apple team.

If you have any queries about the above topic or have to get services and consultations and get flutter app development solutions. Feel free to contact us. AIRO GLOBAL SOFTWARE will be your strong digital partner. E-mail id: [email protected]

enter image description here

Author - Johnson Augustine
Chief Technical Director and Programmer
Founder: Airo Global Software Inc
LinkedIn Profile: www.linkedin.com/in/johnsontaugustine/

How To Install and Setup Flutter?

- Posted in Flutter by

enter image description here

What is Flutter?

Flutter is Google’s portable UI tool for crafting beautiful, natively combined applications for mobile, web, and desktop from a single base code. Flutter works with the existing original code, is used by developers around the world, and is a free and open-source tool.

Why do we use flutter?

  • The same User interface in All Platforms
  • Reduced base code Development Time
  • Increased Time-to-Market Speed
  • Similar to the Native App Performance
  • Custom, Animated UI of Any Complexity Available
  • Own Rendering Engine

This is the reason why you should prefer Flutter for Flutter app development and why you have to choose the best flutter development company for the best services.OK, next we are going through how to install flutter on windows.

What are the System requirements for installing Flutter?

To install and execute Flutter, your development environment must meet these requirements:

  • Operating Systems: Windows 7 SP1
  • Disk Space: 1.64 GB
  • Flutter depends on the below tools being available in your environment. ***** Windows PowerShell ***** Git for windows 2. x

How we Get the Flutter SDK

  1. Download the flutter installation bundle to get the Flutter SDK:
  2. Then you get the Zip file. Extract the zip file and place the contained flutter in the desired installation location for the Flutter SDK

If you don’t need to install a fixed version of the installation process, you can skip the above steps

How to Update your path?

If you want to execute Flutter commands in the regular Windows, take these steps to add Flutter to the path environment variable:

  • From the search bar, enter ‘env’ and select Edit environment variables for your profile.
  • Under the User variable feature check if there is an entry called Path: * If the entry is there, append the path to flutter\bin using; as a separator. * If there is no entry, create a user variable named Path with the path to flutter\bin as its value.

You have to close and restart the existing console windows for these changes to work.

How to run a flutter doctor?

From a console window that has the Flutter directory in the path, run the below command to see if there are platform dependencies you need to fulfill the setup:

content_copy
C:\src\flutter>flutter doctor

The above syntax checks your flutter environment and shows a list of the status of your installation. Check the output for other software you should need to install.

Android setup

How to install Android Studio:

  1. install Android studio
  2. Start the Studio, and go to the ‘Android Studio Setup Wizard’. Keep starting Android SDK Build-Tools, which are needed by Flutter when developing for Android.
  3. Execute flutter doctor to confirm that Flutter has located your installation of Android Studio. If Flutter cannot locate it, run flutter config --android-studio-dir to set the package that Android Studio is installed to.

How to Set up your Android device

To prepare to execute Flutter app on an Android device, you should need an Android device running Android 4.1.

  1. Enable options and USB debugging on the device.
  2. Use a cable to plug your phone into your computer
  3. In the console, run the flutter devices command to verify that Flutter recognizes your connected Android. By default, Flutter uses the version of the Android where your adb tool is based. If you need Flutter to use a different installation of Android SDK, you must set the ANDROID_SDK_ROOT environment variable to that directory.

How to Agree to Android Licenses?

Before you use Flutter, you must sign the licenses of the Android SDK platform. This option should be done after you installed the tools listed in this blog.

  1. Make sure that you have the latest version of Java 8 installed and that your JAVA_HOME environment variable is set to the JDK’s folder.
  2. Android Studio version 2.2 has come with a JDK, so this should already be done.
  3. Review the terms of each license stressfully before agreeing to them.
  4. Once you are done agreeing, run flutter doctor again to confirm that you are ready to use Flutter.

Additional Windows requirements

For Windows desktop development, you need the below in addition to the Flutter SDK:

  • Visual studio. For Win32 you need the “Desktop development with C++” workload installed, including all of its automatic components. For UWP you need the “Universal Windows Platform development” workload installed, with the optional UWP C++ tools.

If you have any questions about the above topic or have to get services and consultations about flutter app development and other digital solutions. Feel free to contact us. AIRO GLOBAL SOFTWARE will be your strong digital partner. E-mail id: [email protected]

enter image description here

Author - Johnson Augustine
Chief Technical Director and Programmer
Founder: Airo Global Software Inc
inkedIn Profile: www.linkedin.com/in/johnsontaugustine/