arcore_flutter_plus

Introducing arcore flutter plus. This package allows you to experience Augmented Reality (AR) on Android devices using Google ARCore.


Key Enhancements (What's New?)

In addition to all the original features, this version includes:

  • Fixed Model Loading: Give support for .glb and .sfb 3d models.
  • Custom Shapes: Added support for new shapes like.
  • Improved Documentation: Clearer examples for distance measurement and interactive model placement.

🙏 Credits & Origin

This package is a upgraded version of the original arcore_flutter_plugin created by gdifrancesco. Since the original package has been inactive for several years, arcore_flutter_plus aims to keep the plugin alive by providing:

  • Compatibility with modern Flutter 3.x versions.
  • Support for updated Android SDKs.
  • New custom features and bug fixes.

GLB Model Loading
3D Model Placement
Distance Measurement
Distance Measurement

🚀 Getting Started

📱 Platform Support

This package is Android-only because it relies on Google's ARCore SDK. (If you are looking for iOS AR support, consider using arkit_plugin)

1. Requirements

  • Android API Level: 24 (Android 7.0) or higher.

2. Installation

Add this to your pubspec.yaml:

dependencies:
  arcore_flutter_plus: ^1.0.0

3. Add Permissions

Ensure your AndroidManifest.xml includes Camera permissions:

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.ar" />

4. Adding assets and models

Add your .glb models to android/app/src/main/assets/.

📖 Usage Example: Placing a Model

ArCoreReferenceNode node = ArCoreReferenceNode(
  name: "Tom",
  object3DFileName: "tom.glb",
  position: vector.Vector3(0, 0, -1.0),
);
arCoreController.addArCoreNode(node);

📱 Example Project

You can find a complete, ready-to-run example project showcasing all features (including distance measurement, placing objects etc.) in the official examples repository:
🔗 arcore_flutter_examples

The simplest code example:

void main() => runApp(
  const MaterialApp(
    debugShowCheckedModeBanner: false,
    //home: AREmojiWorld(), ////-- uncomment to run this example
     home: ARDistanceMeasurer(),
  ),
);

////--Example 1 to calculate distance b/w 2 marks on floor

class ARDistanceMeasurer extends StatefulWidget {
  const ARDistanceMeasurer({super.key});

  @override
  State<ARDistanceMeasurer> createState() => _ARDistanceMeasurerState();
}

class _ARDistanceMeasurerState extends State<ARDistanceMeasurer> {
  ArCoreController? arCoreController;

  // To store 2 points
  ArCoreNode? startNode;
  ArCoreNode? endNode;
  String distanceText = "Tap on floor to place marks";

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('AR Distance Meter')),
      body: Stack(
        children: [
          ArCoreView(
            onArCoreViewCreated: _onArCoreViewCreated,
            enableTapRecognizer: true,
            enablePlaneRenderer: true, // this will show dots
            planeColor: Colors.red,
          ),

          // Distance display karne ke liye UI
          Positioned(
            top: 50,
            left: 20,
            child: Container(
              padding: const EdgeInsets.all(12),
              color: Colors.black54,
              child: Text(
                distanceText,
                style: const TextStyle(color: Colors.white, fontSize: 18),
              ),
            ),
          ),
          Positioned(
            bottom: 30,
            left: 20,
            child: FloatingActionButton(
              onPressed: _resetMarks,
              child: const Icon(Icons.refresh),
            ),
          ),
        ],
      ),
    );
  }

  void _onArCoreViewCreated(ArCoreController controller) {
    arCoreController = controller;
    // Plane detection configuration
    arCoreController?.onPlaneTap = _handleOnPlaneTap;
  }

  void _handleOnPlaneTap(List<ArCoreHitTestResult> hits) {
    if (hits.isEmpty) return;
    final hit = hits.first;

    if (startNode == null) {
      // 1st mark
      startNode = _createMark(hit.pose.translation, Colors.red);
      arCoreController?.addArCoreNode(startNode!);
      setState(() {
        distanceText = "First mark placed. Tap for second mark.";
      });
    } else if (endNode == null) {
      // 2nd mark
      endNode = _createMark(hit.pose.translation, Colors.blue);
      arCoreController?.addArCoreNode(endNode!);

      // Distance calculate
      _calculateDistance();
    }
  }

  ArCoreNode _createMark(vector.Vector3 position, Color color) {
    final material = ArCoreMaterial(color: color, metallic: 1.0);
    final sphere = ArCoreSphere(materials: [material], radius: 0.03);
    return ArCoreNode(shape: sphere, position: position);
  }

  void _calculateDistance() {
    if (startNode == null || endNode == null) return;

    // .value lagana zaroori hai kyunki position ek ValueNotifier hai
    final startPos = startNode!.position!.value;
    final endPos = endNode!.position!.value;

    // Distance Formula implementation
    double dx = endPos.x - startPos.x;
    double dy = endPos.y - startPos.y;
    double dz = endPos.z - startPos.z;

    // math.sqrt use  as prefix imported hai
    double distance = math.sqrt(dx * dx + dy * dy + dz * dz);

    setState(() {
      distanceText = "Distance: ${(distance * 100).toStringAsFixed(2)} cm";
    });
  }

  void _resetMarks() {
    if (startNode != null)
      arCoreController?.removeNode(nodeName: startNode!.name);
    if (endNode != null) arCoreController?.removeNode(nodeName: endNode!.name);
    startNode = null;
    endNode = null;
    setState(() {
      distanceText = "Marks reset. Tap on floor again.";
    });
  }

  @override
  void dispose() {
    arCoreController?.dispose();
    super.dispose();
  }
}

Documentation

Classes provided by the plugin

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

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

ArCoreView

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

AUGMENTEDFACE STANDARDVIEW

There are 4 properties in it:

  • onArCoreViewCreated
  • enableTapRecognizer
  • enableUpdateListener
  • type

onArCoreViewCreated

This property takes a ArCoreController.


enableTapRecognizer

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


enableUpdateListener

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


type

It is a view type, it is either AUGMENTEDFACE, STANDARDVIEW*. It is set to STANDARDVIEW by default.


ArCoreController

This controller is used to add an ArNode using the addArCoreNode function, add an ArCoreNode with an anchor using the addArCoreNodeWithAnchor function, and also remove a node using the removeNode function.


ArCoreFaceView

It is a stateful widget that returns a ArCoreAndroidView. It has two properties enableAugmentedFaces, onArCoreViewCreated.

Initially, enableAugmentedFaces is set to false. onArCoreViewCreated takes a function with ArCoreController argument.


ArCoreFaceController

It used dispose and loadMesh method to control the FaceView.


ArCoreSphere

It is ArCoreShape, takes a radius & ArCoreMaterial.


ArCoreCylinder

It is an ArCoreShape, takes a radius, height, & ArCoreMaterial.


ArCoreCube

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


ArCoreNode

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


ArCoreMaterial

It is used to describe the outlook of the virtual object created by the user.

It has color,textureBytes, metallic, roughness, reflection.


ArCoreRotatingNode

It is an ArCoreNode with a degreesPerSecond property which is a double value.


ArCorePlane

It takes the x, y coordinate of the plane, ArCorePose & ArCorePlaneType.

There are three types of plane:

  • HORIZONTAL_UPWARD_FACING
  • HORIZONTAL_DOWNWARD_FACING
  • VERTICAL

ArCoreReferenceNode

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


objectUrl

URL of glft object for remote rendering.


object3DFileName

Filename of sfb, glb object in android/app/src/main/assets folder.