
[< Home](../readme.md)


# Integration Guide for `PenNav P&P` Native Android Libraries in Flutter

#### Requirements

- The device must be running Android 7.0 or later.
- The minimum supported Android version is 24.

## Prerequisites
- Flutter SDK installed.
- Basic knowledge of Flutter and Android development.
- PenNav native Android libraries (`Penguin.aar`, `PenguinRenderer.aar`, `PenNavUI.aar`) ready.
- Mapbox Account: Register for a Mapbox account to obtain an access token for Mapbox services.

## Steps



### Step 1: Install Mapbox Maps SDK v10.16.6 for Android

To integrate the Mapbox Maps SDK for Android and obtain authorization, follow these steps:

1. **Register and Obtain Authorization**
   - **Create a Mapbox Account**:
     - Visit the [Mapbox Sign Up page](https://www.mapbox.com/signup/) and register for a free account.
   - **Get Your Access Token**:
     - Log in to your Mapbox account and access your dashboard.
     - Navigate to the "Access Tokens" section.
     - Copy your default access token or create a new token with the required permissions.

2. **Configure Your Access Token**
   - For detailed instructions on setting up your access token in your Android project, refer to the [Mapbox Android Maps Installation guide](https://docs.mapbox.com/android/maps/guides/install/).

3. **Configure your public token**

    One way to provide your public token to Mapbox SDK is by adding it as an Android string resource.

      To add the `<string>` entry to your `strings.xml` :
    ```xml
    <string name="mapbox_access_token" translatable="false" tools:ignore="UnusedResources">[Your-token-key]</string>
    ```


4. **Add Mapbox Repository**

    **1- Open your `settings.gradle.kts` file (top-level file) and add the Mapbox Maven repository to the `dependencyResolutionManagement.repositories` block:**

    ```kotlin
    dependencyResolutionManagement {
        repositories {
            mavenCentral()
            // Add the Mapbox Maven repository
            maven {
                url = uri("https://api.mapbox.com/downloads/v2/releases/maven")
                credentials {
                    username = "mapbox" // The username field should always be "mapbox"
                    password = project.findProperty("mapbox_access_token") as String?
                }
            }
        }
    }
    ```


    

    **2- Configure Credentials**

      Ensure you have a valid Mapbox username and password. You should configure the credentials in your `gradle.properties` file, which is typically located in the root of your project or the `~/.gradle/` directory. Add the following properties to your `gradle.properties` file:

      ```properties
      mapbox_access_token= [Enter-your-token]
      ```

      **3- Add Mapbox SDK Dependency**

      Open your `build.gradle.kts` file (module-level) and add the Mapbox Maps SDK dependency. You will need to include this in the `dependencies` block:

      ```kotlin
      dependencies {
          implementation("com.mapbox.maps:android:10.16.6") 
      }
      ```

    **4- Sync Gradle:**
         Click on "Sync Now" in Android Studio or run `./gradlew sync` from the command line to update your project with these dependencies.

---

### Step 2: Add Native Libraries to Your Flutter Project

1. **Copy Libraries:**
    - Create a `libs` directory if it does not already exist: `android/app/libs`.
    - Copy your `.aar` files (`Penguin.aar`, `PenguinRenderer.aar`, `PenNavUI.aar`) into this `libs` directory.

2. **Update Gradle Files:**

    - **In `android/build.gradle`:**
      Add the following to the `allprojects` section to include the `libs` directory as a repository:
      ```gradle
      allprojects {
          repositories {
              google()
              mavenCentral()
              flatDir {
                  dirs 'libs'
              }
          }
      }
      ```

    - **In `android/app/build.gradle`:**
  
      Add the dependencies for your `.aar` files:
      ```gradle

      dependencies {

              // Embeding the aar files (Penguin libraires)
              
                implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) 
                

              // Pre-request Libraries - Important!

              implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3'
              implementation 'com.squareup.retrofit2:retrofit:2.9.0'
              implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
              implementation 'com.squareup.retrofit2:adapter-java8:2.4.0'
              implementation 'com.google.code.gson:gson:2.8.9'
              implementation 'com.google.android.gms:play-services-location:21.3.0'
              implementation 'com.squareup.okhttp3:okhttp:4.10.0'
              implementation 'androidx.test.ext:junit:1.1.5'
              implementation 'com.android.volley:volley:1.2.1'
              def room_version = "2.4.0-alpha04"
              implementation "androidx.room:room-runtime:$room_version"
              annotationProcessor "androidx.room:room-compiler:$room_version"
              implementation 'net.zetetic:android-database-sqlcipher:4.5.2'
              implementation 'com.intuit.ssp:ssp-android:1.1.0'
              implementation 'com.intuit.sdp:sdp-android:1.1.0'
              implementation 'com.github.bumptech.glide:glide:4.12.0'
              annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'

              implementation 'com.mapbox.maps:android:10.16.6' // Added before

              // Add other dependencies if needed
      }
      ```

    - **Enabling View Binding**
         To enable View Binding in your Android project, follow these steps:

         Open your project's build.gradle file.

         Inside the android block, add the following buildFeatures configuration:
         ```java
         android {
             // Other configurations...

             buildFeatures {
                 viewBinding true
             }
         }
         ```

     - **ProGuard Configuration**
       - it's crucial to configure ProGuard to ensure that the library's classes and interfaces are not obfuscated or removed during the optimization process. Follow these steps to add the necessary ProGuard rules:

       - Open your ProGuard configuration file (proguard-rules.pro) in your Android project.

       - Add the following lines to the file:
         ```java

         -dontwarn penguin.com.pennav.Model.Navigation.NearLandmark

         -keep,includedescriptorclasses class net.sqlcipher.** { *; }
         -keep,includedescriptorclasses interface net.sqlcipher.** { *; }

         -keep class retrofit2.** { *; }
         -keep class okhttp3.** { *; }
         -dontwarn retrofit2.**

         -keep class com.google.gson.** { *; }
         -dontwarn com.google.gson.**

         # Penguin classes
         -keep class com.peng.pennavmap.models.** { *; }
         -keep class com.peng.pennavmap.db.** { *; }
             ```

    - **Sync Gradle:**
         Click on "Sync Now" in Android Studio or run `./gradlew sync` from the command line to update your project with these dependencies.


    ## 4. add permissions

      To ensure the smooth operation of the Plug & Play (P&P) module, a list of permissions must be
      granted. These permissions allow the P&P module to access certain resources and functions on the
      device, and are necessary for the P&P module to function properly.

      Following is the permissions that must be added to <u>**AndroidManifest.xml**</u>

      ```xml
          <uses-permission android:name="android.permission.INTERNET" />
          <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
          <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
          <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
          <uses-permission android:name="android.permission.BLUETOOTH" />
          <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
          <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
          <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
          <uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS" />
      ```

      The request permission the purpose of requesting each one of the outlined in the table below
      | Permission      | Why         | What if dismissed |
      | -----------     | ----------- |   -----------     |
      | INTERNET| To access the internet and connect to remote servers|  is required in order to access remote servers and provide a seamless and reliable experience for our users. By granting this permission, you'll be able to fully utilize the features and functionality of our app |
      |ACCESS_NETWORK_STATE| To check the status of the device's network connection| is necessary for checking the status of the device's network connection. This helps ensure that our app is able to function properly, even when the network connection is unstable or unavailable. By granting this permission, you'll be able to use our app with confidence, knowing that it will work even under challenging network conditions|
      |<p>ACCESS_FINE_LOCATION</p><p>ACCESS_COARSE_LOCATION</p>|<p>To access the device's precise location (GPS and network-based) and it used for calculate turn-by-turn directions and show location on map </p><p>To access the device's approximate location (network-based)</p> | permissions are essential for providing location-based services and features. By granting these permissions, you'll be able to take full advantage of our app's ability to provide turn-by-turn directions, show your location on a map, and more. We take the privacy of your location data very seriously, and will always handle it with the utmost care and respect|
      |<p>BLUETOOTH</p><p>BLUETOOTH_ADMIN</p><p>BLUETOOTH_CONNECT</p><p>BLUETOOTH_SCAN</p>|<p>To access the device's Bluetooth functionality and improve wayfinding inside buildings</p><p>To configure the device's Bluetooth settings</p> <p>To connect to Bluetooth devices</p> <p>To scan for nearby Bluetooth devices</p>| permissions are needed to access and utilize the device's Bluetooth functionality. This allows our app to connect to Bluetooth devices, configure Bluetooth settings, and scan for nearby devices. you'll be able to more easily find your way around and make the most of our app's indoor navigation capabilities |
      |HIGH_SAMPLING_RATE_SENSORS|To access high-sampling rate sensors, such as the device's accelerometer and gyroscope, at a higher frequency rate| is needed to access high-sampling rate sensors, such as the device's accelerometer and gyroscope, at a higher frequency rate. This is necessary for certain features and functionality of our app, such as tracking motion and providing precise measurements. By granting this permission, you'll be able to fully utilize the capabilities of our app|

      Overall, by granting these permissions, you'll be able to fully take advantage of the features and functionality of our app. We appreciate your trust in our app and will always handle your data with the at most care and respect.



---
####   Native Android configuration steps

   - **For detailed instructions on how to configure and initialize the PenNav libraries, please start by checking out the [Configuration Steps](p&p-android.md#configuration-steps). It is important to begin here to ensure a proper setup.**


---

### Step 3: Create the Flutter Platform View Factory View

#### 2.1 Implement the View Factory

- **Create a new Kotlin or Java file** in `android/app/src/main/kotlin/com/yourcompany/yourapp/`.

    - **Kotlin (PenguinViewFactory.kt):**

```kotlin
class PenguinViewFactory(
    private val messenger: BinaryMessenger,
    private val mainActivity: MainActivity
) : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
    override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
        val creationParams = args as Map<String?, Any?>?

        return PenguinView(context, viewId, creationParams, messenger,mainActivity)
    }
}
 ```

 - **Java (PenguinViewFactory.java):**

```java
public class PenguinViewFactory extends PlatformViewFactory {

    private final BinaryMessenger messenger;
    private final MainActivity mainActivity;

    public PenguinViewFactory(BinaryMessenger messenger, MainActivity mainActivity) {
        super(StandardMessageCodec.INSTANCE);
        this.messenger = messenger;
        this.mainActivity = mainActivity;
    }

    @Override
    public PlatformView create(Context context, int viewId, Object args) {
        @SuppressWarnings("unchecked")
        Map<String, Object> creationParams = (Map<String, Object>) args;
        return new PenguinView(context, viewId, creationParams, messenger, mainActivity);
    }
}
 ```


#### 2.2 Implement the Custom View

- **Create a new Kotlin or Java file** in `android/app/src/main/kotlin/com/yourcompany/yourapp/`.

    - **Kotlin (PenguinView.kt):**
      ```kotlin
  
          internal class PenguinView(
          context: Context,
          id: Int,
          creationParams: Map<String?, Any?>?,
          messenger: BinaryMessenger,
          activity: MainActivity
      ) : PlatformView, MethodChannel.MethodCallHandler, PenNavUIDelegate {

          // Review the sample app for full implemntation ...
        }
   
      ```

    - **Java (PenguinView.java):**
      ```java
      public class PenguinView implements PlatformView, MethodChannel.MethodCallHandler, PenNavUIDelegate {

            public PenguinView(Context context
            , int id
            , Map<String?, Object?> creationParams
            , BinaryMessenger messenger
            , MainActivity activity) {
                //....
            }
                // Review the sample app for full implemntation  ...

      }
      ```


### 2.3 Register the Platform View in `MainActivity`

- **Update `MainActivity`** to register the platform view factory.

    - **Kotlin:**
      ```kotlin
      import io.flutter.embedding.android.FlutterActivity
      import io.flutter.embedding.engine.FlutterEngine
  
      class MainActivity : FlutterActivity() {
          override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
              super.configureFlutterEngine(flutterEngine)
  
              flutterEngine.platformViewsController.registry.registerViewFactory(
                  "penguin_lib",
                  PenguinViewFactory(flutterEngine.dartExecutor.binaryMessenger, this)
              )
          }
      }
      ```

    - **Java:**
      ```java
      import io.flutter.embedding.android.FlutterActivity;
      import io.flutter.embedding.engine.FlutterEngine;
  
      public class MainActivity extends FlutterActivity {
          @Override
          public void configureFlutterEngine(FlutterEngine flutterEngine) {
              super.configureFlutterEngine(flutterEngine);
  
              flutterEngine.getPlatformViewsController().getRegistry().registerViewFactory(
                  "penguin_lib",
                  new PenguinViewFactory(flutterEngine.getDartExecutor().getBinaryMessenger(), this)
              );
          }
      }
      ```
---

### Step 4: Use the Platform View in Flutter

- **Modify your Dart code** to use the custom platform view.

  ```dart
  import 'package:flutter/material.dart';
  import 'package:flutter/services.dart';

  void main() {
    runApp(MyApp());
  }

  class MyApp extends StatelessWidget {
    @override
    Widget build(BuildContext context) {

      const viewType = 'penguin_lib';

    final creationParams = <String, dynamic>{};

      return Container(
        child: Platform.isIOS
            ? UiKitView( // Display the Penguin Map for iOS
                viewType: viewType,
                layoutDirection: TextDirection.ltr,
                creationParams: creationParams,
                onPlatformViewCreated: onPlatformViewCreated,
                creationParamsCodec: const StandardMessageCodec(),
              )
            : AndroidView( // Display the Penguin Map for Android
                viewType: viewType,
                layoutDirection: TextDirection.ltr,
                creationParams: creationParams,
                onPlatformViewCreated: onPlatformViewCreated,
                creationParamsCodec: const StandardMessageCodec(),
              ),
                );
         }

  Future<void> onPlatformViewCreated(int id) async {

      }
    }
 
  ```

---

### 5. Test Your Integration

1. **Build and Run Your App:**
    - Compile and run your Flutter app on an Android device or emulator.

2. **Verify the Custom View:**
    - Ensure the custom native view is displayed correctly and interacts as expected.

---

[< Home](../readme.md)