Initial Commit

aamir_dev
Aamir.Muhammad 2 months ago
commit d0709a4c54

2
.gitattributes vendored

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

43
.gitignore vendored

@ -0,0 +1,43 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.pub-cache/
.pub/
/build/
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release

@ -0,0 +1,30 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "5dcb86f68f239346676ceb1ed1ea385bd215fba1"
channel: "stable"
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1
base_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1
- platform: android
create_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1
base_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'

@ -0,0 +1,53 @@
# PenNav (P&P)
Experience top-tier, comprehensive campus-wide navigation with PenNav , featuring detailed 2D/3D maps and seamless home-to-office routing complete with step-by-step directions and tactile feedback. PenNav offers the flexibility to be seamlessly integrated into your current applications or used as a standalone app. PenNav ensures a smooth and effortless setup process, Enabling you to effortlessly customize your navigation solutions to suit your specific requirements.
**Turn-by-turn guidance**
Turn-by-turn, indoor/outdoor real-time blue-dot experience with voice commands. PenNav offers outstanding accuracy and floor-level detection with several routing options.
**Multi-floor routing**
Built from the ground up to support indoor navigation, floor-level detection and multi-floor navigation is at the core of what we do. Offering flexibility in connecting floors and buildings together offers navigation options which are unique and impressive.
**Indoor/outdoor transition**
PenNav offers campus-wide and home-to-office options by leveraging GPS in outdoor navigation with seamless AI-driven indoor/outdoor transition detection.
**Seamless Integration**
PenNav comes in a user-friendly package designed for effortless integration, featuring a vector-based map engine, comprehensive 2D/3D maps, and a full UI/UX experience that reduces integration time from weeks to hours. Its appearance is fully customizable, allowing it to mirror the client's brand through languages, colors, and typography options.
---
## P&P Integration Guide for Flutter
## Overview
The Plug & Play module for Flutter is designed to offer a seamless integration with Penguins various SDKs, enabling quick incorporation into your Flutter applications for both iOS and Android platforms. This document serves as a demonstration of how to utilize the Plug & Play module within a Flutter app, showcasing a typical app structure and the integration process.
**Key components of the demonstration include:**
- **SDK Integration**: Examples of how to integrate PenNav SDKs into your Flutter project.
- **Flutter App Structure**: Guidance on organizing your Flutter app to efficiently use the Plug & Play module.
- **Cross-Platform Compatibility**: Instructions for ensuring the module works seamlessly on both iOS and Android.
This guide will walk you through the steps to effectively implement and utilize the Plug & Play module within your Flutter applications.
---
#### Prerequisites
- **Flutter SDK**: Ensure the Flutter SDK is installed.
- **Flutter Development Knowledge**: A foundational understanding of Flutter development for both iOS and Android platforms.
- **Penguin Native iOS Libraries**: Obtain the following libraries: `Penguin.xcframework`, `PenguinRenderer.xcframework`, and `PenNavUI.xcframework`.
- **PenNav Native Android Libraries**: Ensure the following libraries are available: `Penguin.aar`, `PenguinRenderer.aar`, and `PenNavUI.aar`.
- **Mapbox Account**: Register for a Mapbox account to acquire an access token required for Mapbox services.
---
- ### [iOS Integration Guide for Flutter](doc/ios.md)
This guide provides comprehensive instructions for integrating our native iOS libraries into a Flutter project. It details the steps required to set up and configure the libraries, ensuring they work seamlessly with your Flutter application on iOS.
- ### [Android Integration Guide for Flutter](doc/android.md)
This guide offers detailed instructions for incorporating our native Android libraries into a Flutter project. It covers the configuration and integration process, enabling smooth interaction between our libraries and your Flutter application on Android.

@ -0,0 +1,28 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

13
android/.gitignore vendored

@ -0,0 +1,13 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties
**/*.keystore
**/*.jks

@ -0,0 +1,133 @@
plugins {
id "com.android.application"
id "kotlin-android"
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id "dev.flutter.flutter-gradle-plugin"
}
def localProperties = new Properties()
def localPropertiesFile = rootProject.file("local.properties")
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader("UTF-8") { reader ->
localProperties.load(reader)
}
}
def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
if (flutterVersionCode == null) {
flutterVersionCode = "1"
}
def flutterVersionName = localProperties.getProperty("flutter.versionName")
if (flutterVersionName == null) {
flutterVersionName = "1.0"
}
android {
namespace = "com.eventtan.test.penguin_flutter_sample"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
buildFeatures {
viewBinding true
dataBinding true
buildConfig true
}
kotlinOptions {
jvmTarget = '17'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.eventtan.test.penguin_flutter_sample"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdk = 24
targetSdk = flutter.targetSdkVersion
versionCode = flutterVersionCode.toInteger()
versionName = flutterVersionName
}
signingConfigs {
release {
storeFile file("key.jks")
storePassword "123456"
keyAlias "key0"
keyPassword "123456"
}
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
debug {
debuggable true
minifyEnabled true
signingConfig signingConfigs.release
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
flutter {
source = "../.."
}
dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
implementation 'androidx.appcompat:appcompat:1.4.0'
implementation 'com.google.android.material:material:1.9.0'
implementation"androidx.multidex:multidex:2.0.1"
// Penguin Pre-libraries
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.0.1'
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'
implementation files('libs/PenNavUI.aar')
implementation files('libs/Penguin.aar')
implementation files('libs/PenguinRenderer.aar')
}

Binary file not shown.

Binary file not shown.

@ -0,0 +1,49 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-dontwarn org.bouncycastle.jsse.BCSSLParameters
-dontwarn org.bouncycastle.jsse.BCSSLSocket
-dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider
-dontwarn org.conscrypt.Conscrypt$Version
-dontwarn org.conscrypt.Conscrypt
-dontwarn org.conscrypt.ConscryptHostnameVerifier
-dontwarn org.openjsse.javax.net.ssl.SSLParameters
-dontwarn org.openjsse.javax.net.ssl.SSLSocket
-dontwarn org.openjsse.net.ssl.OpenJSSE
-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.** { *; }

@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

@ -0,0 +1,66 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<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" />
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>
<application
android:usesCleartextTraffic="true"
android:label="penguin_flutter_sample"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
android:hardwareAccelerated="true"
android:largeHeap="true"
tools:replace="android:label">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:label="penguin_flutter_sample"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
</manifest>

@ -0,0 +1,66 @@
package com.eventtan.test.penguin_flutter_sample
import android.content.Intent
import android.content.pm.PackageManager
import android.util.Log
import com.eventtan.app.penguin_flutter_sample.penguin.PenguinViewFactory
import com.eventtan.test.penguin_flutter_sample.PermissionManager.PermissionHelper
import com.eventtan.test.penguin_flutter_sample.PermissionManager.PermissionManager
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
/**
* The main activity for the Flutter application.
* This activity is responsible for configuring the Flutter engine and registering platform view factories.
*/
class MainActivity : FlutterActivity() {
private lateinit var flutterEngine: FlutterEngine
/**
* Configures the Flutter engine by registering platform view factories.
*
* @param flutterEngine The [FlutterEngine] instance associated with this activity.
*/
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
flutterEngine.platformViewsController.registry.registerViewFactory(
"penguin_lib", // Unique identifier for the view factory
PenguinViewFactory(
flutterEngine.dartExecutor.binaryMessenger, // Used for communication with Dart
this // Reference to the current MainActivity
)
)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
val granted = grantResults.all { it == PackageManager.PERMISSION_GRANTED }
val intent = Intent("PERMISSION_RESULT_ACTION").apply {
putExtra("PERMISSION_GRANTED", granted)
}
sendBroadcast(intent)
// Log the request code and permission results
Log.d("PermissionsResult", "Request Code: $requestCode")
Log.d("PermissionsResult", "Permissions: ${permissions.joinToString()}")
Log.d("PermissionsResult", "Grant Results: ${grantResults.joinToString()}")
}
}

@ -0,0 +1,21 @@
package com.eventtan.test.penguin_flutter_sample.PermissionManager
import android.Manifest
object PermissionHelper {
fun getRequiredPermissions(): Array<String> {
return arrayOf(
Manifest.permission.INTERNET,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_NETWORK_STATE,
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN,
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_CONNECT,
Manifest.permission.HIGH_SAMPLING_RATE_SENSORS,
Manifest.permission.ACTIVITY_RECOGNITION
)
}
}

@ -0,0 +1,50 @@
package com.eventtan.test.penguin_flutter_sample.PermissionManager
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
class PermissionManager(
private val context: Context,
val listener: PermissionListener,
private val requestCode: Int,
vararg permissions: String
) {
private val permissionsArray = permissions
interface PermissionListener {
fun onPermissionGranted()
fun onPermissionDenied()
}
fun arePermissionsGranted(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
permissionsArray.all {
ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
}
} else {
true
}
}
fun requestPermissions(activity: Activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
ActivityCompat.requestPermissions(activity, permissionsArray, requestCode)
}
}
fun handlePermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
if (this.requestCode == requestCode) {
val allGranted = grantResults.all { it == PackageManager.PERMISSION_GRANTED }
if (allGranted) {
listener.onPermissionGranted()
} else {
listener.onPermissionDenied()
}
}
}
}

@ -0,0 +1,15 @@
package com.eventtan.test.penguin_flutter_sample.PermissionManager
// PermissionResultReceiver.kt
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
class PermissionResultReceiver(
private val callback: (Boolean) -> Unit
) : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val granted = intent?.getBooleanExtra("PERMISSION_GRANTED", false) ?: false
callback(granted)
}
}

@ -0,0 +1,230 @@
package com.eventtan.app.penguin_flutter_sample.penguin
import android.app.Activity
import android.content.Context
import android.content.IntentFilter
import android.graphics.Color
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.widget.RelativeLayout
import android.widget.Toast
import com.eventtan.test.penguin_flutter_sample.MainActivity
import com.eventtan.test.penguin_flutter_sample.PermissionManager.PermissionHelper
import com.eventtan.test.penguin_flutter_sample.PermissionManager.PermissionManager
import com.eventtan.test.penguin_flutter_sample.PermissionManager.PermissionResultReceiver
import com.peng.pennavmap.PlugAndPlayConfiguration
import com.peng.pennavmap.PlugAndPlaySDK
import com.peng.pennavmap.enums.InitializationErrorType
import com.peng.pennavmap.interfaces.PenNavUIDelegate
import com.peng.pennavmap.utils.Languages
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.platform.PlatformView
/**
* Custom PlatformView for displaying Penguin UI components within a Flutter app.
* Implements `PlatformView` for rendering the view, `MethodChannel.MethodCallHandler` for handling method calls,
* and `PenNavUIDelegate` for handling SDK events.
*/
internal class PenguinView(
context: Context,
id: Int,
creationParams: Map<String?, Any?>?,
messenger: BinaryMessenger,
activity: MainActivity
) : PlatformView, MethodChannel.MethodCallHandler, PenNavUIDelegate {
// The layout for displaying the Penguin UI
private val mapLayout: RelativeLayout = RelativeLayout(context)
private val _context: Context = context.applicationContext
private val permissionResultReceiver: PermissionResultReceiver
private val permissionIntentFilter = IntentFilter("PERMISSION_RESULT_ACTION")
private companion object {
const val PERMISSIONS_REQUEST_CODE = 1
}
private lateinit var permissionManager: PermissionManager
// Reference to the main activity
private var _activity: Activity = activity
private lateinit var mContext: Context
init {
// Set layout parameters for the mapLayout
mapLayout.layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
)
mContext = (_activity as MainActivity).context
permissionResultReceiver = PermissionResultReceiver { granted ->
if (granted) {
onPermissionsGranted()
} else {
onPermissionsDenied()
}
}
mContext.registerReceiver(permissionResultReceiver, permissionIntentFilter)
// Set the background color of the layout
mapLayout.setBackgroundColor(Color.RED)
permissionManager = PermissionManager(
context = mContext,
listener = object : PermissionManager.PermissionListener {
override fun onPermissionGranted() {
// Handle permissions granted
onPermissionsGranted()
}
override fun onPermissionDenied() {
// Handle permissions denied
onPermissionsDenied()
}
},
requestCode = PERMISSIONS_REQUEST_CODE,
*PermissionHelper.getRequiredPermissions()
)
if (!permissionManager.arePermissionsGranted()) {
permissionManager.requestPermissions(_activity)
} else {
// Permissions already granted
permissionManager.listener.onPermissionGranted()
}
}
private fun onPermissionsGranted() {
// Handle the actions when permissions are granted
Log.d("PermissionsResult", "onPermissionsGranted")
// Register the platform view factory for creating custom views
// Initialize the Penguin SDK
initPenguin()
}
private fun onPermissionsDenied() {
// Handle the actions when permissions are denied
Log.d("PermissionsResult", "onPermissionsDenied")
}
/**
* Returns the view associated with this PlatformView.
*
* @return The main view for this PlatformView.
*/
override fun getView(): View {
return mapLayout
}
/**
* Cleans up resources associated with this PlatformView.
*/
override fun dispose() {
// Cleanup code if needed
}
/**
* Handles method calls from Dart code.
*
* @param call The method call from Dart.
* @param result The result callback to send responses back to Dart.
*/
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
// Handle method calls from Dart code here
}
/**
* Initializes the Penguin SDK with custom configuration and delegates.
*/
private fun initPenguin() {
// Configure the PlugAndPlaySDK
PlugAndPlaySDK.configuration = PlugAndPlayConfiguration.Builder()
.setBaseUrl("https://temp.penguinin.com", "https://temp.penguinin.com")
.setServiceName("api", "pe")
.setClientData("Client", "clientkey")
.setUserName("client")
.setLanguageID(Languages.en)
.setSimulationModeEnabled(true)
.setEnableBackButton(true)
.setDeepLinkData("deeplink")
.setCustomizeColor("#2CA0AF")
.setDeepLinkSchema("")
.setDeepLinkData(null)
.build()
// Set location delegate to handle location updates
PlugAndPlaySDK.setPiLocationDelegate {
// Example code to handle location updates
// Uncomment and modify as needed
// if (location.size() > 0)
// Toast.makeText(_context, "Location Info Latitude: ${location[0]}, Longitude: ${location[1]}", Toast.LENGTH_SHORT).show()
}
// Set events delegate for reporting issues
PlugAndPlaySDK.setPiEventsDelegate { }
// Start the Penguin SDK
PlugAndPlaySDK.start(mContext, this)
}
/**
* Called when Penguin UI setup is successful.
*
* @param warningCode Optional warning code received from the SDK.
*/
override fun onPenNavSuccess(warningCode: String?) {
if (_context is Activity) {
_context.runOnUiThread {
Toast.makeText(_context, "Success Info: $warningCode", Toast.LENGTH_SHORT).show()
}
} else {
val handler = Handler(Looper.getMainLooper())
handler.post {
Toast.makeText(_context, "Success Info: $warningCode", Toast.LENGTH_SHORT).show()
}
}
}
/**
* Called when there is an initialization error with Penguin UI.
*
* @param description Description of the error.
* @param errorType Type of initialization error.
*/
override fun onPenNavInitializationError(
description: String?,
errorType: InitializationErrorType?
) {
Toast.makeText(mContext, "Navigation Error: $description", Toast.LENGTH_SHORT).show()
}
/**
* Called when Penguin UI is dismissed.
*/
override fun onPenNavUIDismiss() {
// Handle UI dismissal if needed
try {
mContext.unregisterReceiver(permissionResultReceiver)
dispose();
} catch (e: IllegalArgumentException) {
Log.e("PenguinView", "Receiver not registered: $e")
}
}
}

@ -0,0 +1,38 @@
package com.eventtan.app.penguin_flutter_sample.penguin
import android.content.Context
import com.eventtan.test.penguin_flutter_sample.MainActivity
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.StandardMessageCodec
import io.flutter.plugin.platform.PlatformView
import io.flutter.plugin.platform.PlatformViewFactory
// PenguinViewFactory.kt
/**
* A factory class for creating instances of [PenguinView].
*
* @property messenger The [BinaryMessenger] used for communication.
* @property mainActivity The [MainActivity] instance associated with this view.
*/
class PenguinViewFactory(
private val messenger: BinaryMessenger,
private val mainActivity: MainActivity
) : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
/**
* Creates a new [PenguinView] instance.
*
* @param context The [Context] in which the view is running.
* @param viewId The unique ID of the view to be created.
* @param args Optional arguments passed for creating the view, expected to be a [Map].
* @return A new instance of [PenguinView].
*/
override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
// Cast the arguments to a Map if they are provided
val creationParams = args as Map<String?, Any?>?
// Instantiate and return the PenguinView with the provided parameters
return PenguinView(context, viewId, creationParams, messenger, mainActivity)
}
}

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="btnLanguage">#EFEFEF</color>
<color name="mainPengColor">#2CA0AF</color>
<color name="red">#d32f2f</color>
<color name="com_penguin_nav_demo_transparent">#00000000</color>
<color name="com_penguin_nav_demo_amber">#FFC107</color>
<color name="com_penguin_nav_demo_pen_blue">#3392E2</color>
<color name="com_penguin_nav_demo_green">#53973B</color>
<color name="com_penguin_nav_demo_pen_line_dark_red">#DC0000</color>
<color name="com_penguin_nav_demo_pen_gray_line">#E5E4E4</color>
</resources>

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="com_penguin_nav_demo_10dp">10.00dp</dimen>
<dimen name="com_penguin_nav_demo_15dp">15.00dp</dimen>
<dimen name="com_penguin_nav_demo_16dp">16.00dp</dimen>
<dimen name="com_penguin_nav_demo_25dp">25.00dp</dimen>
<dimen name="com_penguin_nav_demo_40dp">40.00dp</dimen>
<dimen name="com_penguin_nav_demo_60dp">60.00dp</dimen>
</resources>

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Penguin_flutter_Sample</string>
/////////////////////////////////////////////////
<!--setupConfiguration-->
<string name="data_url" translatable="false">https://temp.nav.penguinin.com</string>
<string name="data_service_name" translatable="false">api</string>
<string name="position_url" translatable="false">https://temp.nav.penguinin.com</string>
<string name="position_service_name" translatable="false">pe</string>
<string name="client_id" translatable="false">PIF</string>
<string name="client_key" translatable="false">UGVuZ3VpbklOX1Blbk5hdl9QSUY=</string>
<string name="deep_link_schema" translatable="false"></string>
<string name="deep_link_domain" translatable="false"></string>
<string name="mapbox_access_token" translatable="false">mapbox_token</string>
////////////////////////////////////////////
</resources>

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
<style name="LaunchTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="LaunchTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
<style name="LaunchTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
</resources>

@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

@ -0,0 +1,57 @@
buildscript {
repositories {
google()
mavenCentral()
maven { url 'https://plugins.gradle.org/m2' }
// maven { url 'https://jitpack.io' }
maven {
url 'https://api.mapbox.com/downloads/v2/releases/maven'
authentication {
basic(BasicAuthentication)
}
credentials {
username = 'mapbox'
password = "sk.eyJ1IjoidmlyYWwtbW9ibWF4aW1lIiwiYSI6ImNseWZ0MzByYTAzZ2MyeHMxMXp3NWRscWYifQ.Dq-SRE-hyED1ojrJcq3JKA"
if (password == null || password == "") {
throw new GradleException("MAPBOX_DOWNLOADS_TOKEN isn't set. Set it to the project properties or to the enviroment variables.")
}
}
}
}
dependencies {
classpath "com.mapbox.gradle.plugins:access-token:0.4.0"
}
}
allprojects {
repositories {
google()
mavenCentral()
maven { url 'https://plugins.gradle.org/m2' }
maven {
url 'https://api.mapbox.com/downloads/v2/releases/maven'
authentication {
basic(BasicAuthentication)
}
credentials {
username = 'mapbox'
password = "sk.eyJ1IjoidmlyYWwtbW9ibWF4aW1lIiwiYSI6ImNseWZ0MzByYTAzZ2MyeHMxMXp3NWRscWYifQ.Dq-SRE-hyED1ojrJcq3JKA"
if (password == null || password == "") {
throw new GradleException("MAPBOX_DOWNLOADS_TOKEN isn't set. Set it to the project properties or to the enviroment variables.")
}
}
}
}
}
rootProject.layout.buildDirectory = file('../build')
subprojects {
project.layout.buildDirectory = file("${rootProject.layout.buildDirectory.get().asFile}/${project.name}")
}
subprojects {
project.evaluationDependsOn(':app')
}
tasks.register("clean", Delete) {
delete rootProject.layout.buildDirectory
}

@ -0,0 +1,8 @@
org.gradle.jvmargs=-Xmx4G -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true
android.nonTransitiveRClass=false
android.nonFinalResIds=false
MAPBOX_USER_NAME = "mapbox"
MAPBOX_DOWNLOADS_TOKEN="sk.eyJ1IjoidmlyYWwtbW9ibWF4aW1lIiwiYSI6ImNseWZ0MzByYTAzZ2MyeHMxMXp3NWRscWYifQ.Dq-SRE-hyED1ojrJcq3JKA"

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-all.zip

@ -0,0 +1,44 @@
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}()
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
maven { url 'https://plugins.gradle.org/m2' }
maven { url 'https://jitpack.io' }
maven {
url 'https://api.mapbox.com/downloads/v2/releases/maven'
credentials {
username = 'mapbox'
password = 'sk.eyJ1IjoidmlyYWwtbW9ibWF4aW1lIiwiYSI6ImNseWZ0MzByYTAzZ2MyeHMxMXp3NWRscWYifQ.Dq-SRE-hyED1ojrJcq3JKA'
if (password == null || password == "") {
throw new GradleException("MAPBOX_DOWNLOADS_TOKEN isn't set. Set it to the project properties or to the enviroment variables.")
}
}
authentication {
basic(BasicAuthentication)
}
}
jcenter()
}
}
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.1.4" apply false
id "org.jetbrains.kotlin.android" version "1.8.22" apply false
}
include ":app"
//include ':pennavui'
//include ':penguin_sdk'
//include ':renderer'

@ -0,0 +1,3 @@
description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:

@ -0,0 +1,419 @@
[< 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)

@ -0,0 +1,320 @@
[< Back](../readme.md)
# Integration Guide for `PenNav P&P` Native iOS Libraries in Flutter
#### Requirements
- iOS 13.0 or later
- iPadOS 13.0 or later
#### Prerequisites
- Flutter SDK installed.
- Basic knowledge of Flutter and iOS development.
- Penguin native iOS libraries (Penguin.xcframework, PenguinRenderer.xcframework, PenNavUI.xcframework).
- Mapbox Account: Register for a Mapbox account to obtain an access token for Mapbox services.
## Steps
### **Step 1 : Install Mapbox Maps SDK v10.6.4 for iOS**
To install the Mapbox Maps SDK for iOS and get authorization, follow these steps:
#### **1. Register and Get Authorization**
1. **Create a Mapbox Account:**
- Go to [Mapbox's Sign Up page](https://www.mapbox.com/signup/) and create a free account.
2. **Get Your Access Token:**
- After logging in, go to your [Mapbox account dashboard](https://account.mapbox.com/).
- Navigate to the "Access Tokens" section.
- Copy your default access token or create a new token with the desired permissions.
3. **Set Up Your Secret Token (Important)**
- For guidance on configuring your secret token, please refer to the Mapbox installation guide at: [Mapbox iOS Maps Installation](https://docs.mapbox.com/ios/maps/guides/install/).
4. **Configure your public token**
To configure your public access token, follow these steps:
- Open your project's Info.plist file
- Hover over a key and click the plus button
- Type MBXAccessToken into the key field
- Click the value field and paste in your public access token.
<video width="640" height="480" controls>
<source src="https://docs.mapbox.com/ios/assets/medias/MapsInstallPublicToken-eb2f6fbf8715def5ae8eaa35a5b562c4.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
---
### **Step 2 : Add Native Libraries to Your Flutter Project**
1. **Create the Frameworks Folder:**
- Open Finder and navigate to your Flutter projects `ios` directory.
- Right-click inside the `ios` folder, select **New Folder**, and name the folder **Frameworks**.
2. **Move .xcframework Files:**
- Locate your `.xcframework` files in Finder.
- Select the files, right-click, and choose **Copy**.
- Navigate to the newly created **Frameworks** folder.
- Right-click inside the **Frameworks** folder and select **Paste** to move the files.
#### Update the Xcode Project
1. **Open Xcode Workspace:**
- Open the `ios/Runner.xcworkspace` file in Xcode.
2. **Add .xcframework Files to Xcode:**
- Drag and drop the `.xcframework` files into the "Frameworks" group in the Xcode project navigator.
- Ensure the **Copy items if needed** checkbox is selected.
#### Update Build Settings
1. **Configure Framework Search Paths:**
- Select the **Runner** target in Xcode.
- Go to the **Build Settings** tab.
- Add `$(SRCROOT)/Frameworks` to the **Framework Search Paths**.
2. **Verify Framework Embedding:**
- In the **General** tab of the Runner target, check that the frameworks are listed under **Frameworks, Libraries, and Embedded Content**.
- Ensure the frameworks are set to **Embed & Sign**.
---
### **Step 3 : Configuring Privacy Permissions in `Info.plist`**
In the iOS project, modify the `Info.plist` file to include the following keys. Set their data types to `String` and provide descriptive values that explain the necessity of your app's access to these privacy-sensitive resources:
- `NSLocationAlwaysAndWhenInUseUsageDescription`
- `NSLocationWhenInUseUsageDescription`
- `NSBluetoothAlwaysUsageDescription`
- `NSMotionUsageDescription`
Ensure that each key is assigned a string value detailing the purpose for which your application requires access to the respective data.
---
### **Step 4 : Modify the Podfile**
1. Navigate to your Flutter project's `ios` directory:
```sh
cd path/to/your/flutter/project/ios
```
2. Open the `Podfile` in a text editor:
```sh
open Podfile
```
3. Update your `Podfile` to include the Mapbox Maps SDK dependency and apply the necessary build setting. Your `Podfile` should look like this:
```ruby
target 'Runner' do
use_frameworks!
use_modular_headers!
pod 'MapboxMaps', '10.16.4'
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
end
end
end
```
#### **3. Install CocoaPods Dependencies**
1. Install the CocoaPods dependencies by running:
```sh
pod install
```
2. This will create or update the `Pods` directory and the `.xcworkspace` file.
#### **4. Open the Xcode Workspace**
1. Open the generated `.xcworkspace` file to make sure the Mapbox SDK is correctly integrated:
```sh
open Runner.xcworkspace
```
2. Always use this `.xcworkspace` file to open your project in Xcode, as it includes the CocoaPods dependencies.
---
#### Native iOS configuration steps
- **For detailed instructions on how to configure and initialize the Penguin SDKs, please start by checking out the [Configuration Steps](configuringPanNavUI.md#configuration-steps). It is important to begin here to ensure a proper setup.**
---
### **Step 5 : Create the Flutter Platform View Factory View**
- **Implement the View Factory:**
Create `PenguinViewFactory.swift` in `ios/Runner`.
```swift
import Flutter
import UIKit
class PenguinViewFactory: NSObject, FlutterPlatformViewFactory {
private var messenger: FlutterBinaryMessenger
init(messenger: FlutterBinaryMessenger) {
self.messenger = messenger
super.init()
}
func create(
withFrame frame: CGRect,
viewIdentifier viewId: Int64,
arguments args: Any?
) -> FlutterPlatformView {
return PenguinView(
frame: frame,
viewIdentifier: viewId,
arguments: args,
binaryMessenger: messenger)
}
public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol {
return FlutterStandardMessageCodec.sharedInstance()
}
}
```
---
### **Step 6 : Implement the Custom View:**
Create `PenguinView.swift` in `ios/Runner`.
```swift
import Flutter
import UIKit
class PenguinView: NSObject, FlutterPlatformView {
private var _view: UIView
init(
frame: CGRect,
viewIdentifier viewId: Int64,
arguments args: Any?,
binaryMessenger messenger: FlutterBinaryMessenger?
) {
_view = UIView()
super.init()
// Initialize and configure the view using Penguin libraries
// Example:
// let penguinView = PenguinLibraryView(frame: frame)
// _view.addSubview(penguinView)
}
func view() -> UIView {
return _view
}
}
```
---
### **Step 7 : Register the Platform View in AppDelegate**
- **Modify `AppDelegate.swift`:**
```swift
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
let penguinFactory = PenguinViewFactory(messenger: self.registrar(forPlugin: "penguin")!.messenger())
self.registrar(forPlugin: "PenguinView")!.register(penguinFactory, withId: "penguin_lib")
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
```
---
### **Step 8 : Use the Platform View in Flutter**
- **Modify Your Dart Code:**
```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 MaterialApp(
home: Scaffold(
body: Container(
child: Platform.isIOS
? UiKitView(
viewType: viewType,
layoutDirection: TextDirection.ltr,
creationParams: creationParams,
onPlatformViewCreated: onPlatformViewCreated,
creationParamsCodec: const StandardMessageCodec(),
)
: AndroidView(
viewType: viewType,
layoutDirection: TextDirection.ltr,
creationParams: creationParams,
onPlatformViewCreated: onPlatformViewCreated,
creationParamsCodec: const StandardMessageCodec(),
),
),
),
);
}
Future<void> onPlatformViewCreated(int id) async {
// Handle platform view creation
}
}
```
### **Test Your Integration**
- Build and run your app on an iOS device or simulator.
- Verify that the custom native view appears and functions as expected.
### Tips:
- Ensure all framework dependencies are correctly resolved.
- Check that you have the appropriate permissions and entitlements if required by the native libraries.
- Debug using Xcode if you encounter any issues related to the view or integration.
[< Back](../readme.md)

@ -0,0 +1,210 @@
[< Back](android.md)
## Integrating and Configuring PenNavUI
## 5. Run the Plug & Play (P&P) Module
To implement the PenNavUIDelegate interface in your Java project and begin calling the P&P
functions, follow this steps:
1. From your project implement the PenNavUIDelegate to start calling the P&P functions
```java
public class MyClass implements PenNavUIDelegate {}
```
2. In the class where you implement the PenNavUIDelegate interface, you need to call three
functions :
a. **onPenNavSuccess** : The triggering of this callback signifies the successful initialization of
the P&P module.
```java
@Override
public void onPenNavSuccess(String warning) {}
```
b. **onPenNavInitializationError** : callback is triggered upon the failure of the P&P module
initialization process.
```java
@Override
public void onPenNavInitializationError(String description, InitializationErrorType errorType) {}
```
c. **onPenNavUIDismiss** : callback is triggered upon the successful closure of the P&P module, which
is initiated by the clicking of the back button.
```java
@Override
public void onPenNavUIDismiss() {}
```
3. Setup the P&P configuration using **PlugAndPlayConfiguration.Builder**
```java
private PlugAndPlayConfiguration.Builder builder=new PlugAndPlayConfiguration.Builder();
```
4. From the class that used to start the P&P module,setup the P&P configurations
There are two types of configurations (mandatory and optional).
a. Mandatory configuration : if these configurations are not setup , the P&P module
initialization will fail
```java
PlugAndPlaySDK.configuration = builder
.setBaseUrl(dataServerUrl, positionServerUrl)
.setServiceName(dataServiceName,positionServiceName)
.setClientData(clientID, clientKey)
.setUserName(name)
```
| Config | Link |
|----------------|----------------------------------------------------|
| setBaseUrl | [description](./readmeresources/setBaseUrl.md) |
| setServiceName | [description](./readmeresources/setServiceName.md) |
| setClientData | [description](./readmeresources/setClientData.md) |
| setUserName | [description](./readmeresources/setUserName.md) |
b. And other optional configurations, you have the option to add them or ignore them and it will not affect the app performance
```java
builder.setSimulationModeEnabled(isSimulation)
.setLanguageID(languageCode)
.setCustomizeColor(hexCode)
.setDeepLinkSchema(deepLinkSchema)
.setDeepLinkData(deepLinkReceivedData)
```
| Config | Link |
|--------------------------|-------------------------------------------------------|
| setSimulationModeEnabled | [description](./readmeresources/setSimulationMode.md) |
| setLanguageID | [description](./readmeresources/setLanguage.md) |
| setCustomizeColor | [description](./readmeresources/setCustomizeColor.md) |
| setDeepLinkData | [description](./readmeresources/setDeepLinkData.md) |
| setDeepLinkSchema | [description](./readmeresources/setDeepLinkSchema.md) |
**After Setting configuration**
You need to build the configuration
```java
builder.build()
```
**Start initializing our SDK**
Call the initialize(Context, PenNavUIDelegate) method providing an object that implements PenNavUIDelegate.
```java
PlugAndPlaySDK.start(Context,PenNavUIDelegate);
```
## 6. Possibly another implementation is needed
### 1. Implementing the Off Location Campus Delegate
In this callBack if the user is offCampus you can get the location as (Latitude and Longitude)
Take the following steps to get notified if the user location is off-campus:
1. From your project Implement the `PILocationDelegate` interface and
its `onLocationOffCampus(ArrayList<Double> location)` method that gets called back when the user
location is off-campus with an array of floating-point numbers as a parameter that represents
off-campus latitude and longitude.
```java
public class MyClass extends AppCompatActivity implements PILocationDelegate
```
2. In the class where you implement the PILocationDelegate interface, you can call one method
```java
public class MyClass extends AppCompatActivity implements PILocationDelegate {
@Override
public void onLocationOffCampus(ArrayList<Double> location) {}
}
```
You will receive an arrayList of double points of Latitude and longitude
Example of how you can use the data :
```java
if (location.size() > 0)
Toast.makeText(mContext , "Location Info Latitude : " + location.get(0) + " longitude : " + location.get(1) , Toast.LENGTH_SHORT).show();
```
And the data will shown as :
Location Info Latitude : 31.656546 longitude : 35.46146
3. During the map initializing step, set the `PILocationDelegate` in the `setPiLocationDelegate`
method to an object that implements the `PILocationDelegate` interface and
its `ArrayList<Double> location)` method.
```java
PlugAndPlaySDK.setPiLocationDelegate(PILocationDelegate);
```
### 2. Navigating to Places on the Map
**Using Reference IDs**
You can use this method From PlugAndPlaySDK class and use it if you want to show the Poi on the map
and navigate to it
Call the `navigateTo(Context mContext, String referenceID, Completion completion)` method to
navigate to a place given its reference ID.
```java
PlugAndPlaySDK.navigateTo(Context,String,Completion)
```
**Using shared Links**
1. Provide a shared link for plug-and-play to share user or Poi location on the map using
the `setDeepLinkSchema(String)` method
```java
PlugAndPlayConfiguration.Builder().setDeepLinkSchema(String)
```
2. Provide data from a deep link to display places on the map using the `setDeepLinkData(String)`
method
```java
PlugAndPlayConfiguration.Builder().setDeepLinkData(String)
```
### 3. Reporting an Issue
The PlugAndPlaySDK provides a flexible way to capture and report issues within your application. By using a delegate, you can seamlessly integrate third-party tools
or your end point to streamline the process of issue reporting and debugging.
#### Setting Up the Delegate
To enable issue reporting with PlugAndPlaySDK, you need to set up a delegate by calling the `setPiEventsDelegate` method. The delegate is responsible for handling issue reports. Here's the basic setup:
```java
PlugAndPlaySDK.setPiEventsDelegate(new PIEventsDelegate() {
@Override
public void onReportIssue(PIReportIssue issue) {
// Implement issue reporting logic here
}
});
```
In this code snippet, we define an anonymous inner class that implements the `PIEventsDelegate` interface. The `onReportIssue` method is where you will place the logic for reporting issues to your chosen tool.
#### Controlling Report Issue Buttons in PlugAndPlaySDK
You can easily enable or disable report issue buttons in PlugAndPlaySDK based on your application's needs.
#### Usage
- **Enable Report Issue Buttons**:
```java
PlugAndPlaySDK.setReportingIssuesEnabled(true);
```
Use this when you want users to report issues.
- **Disable Report Issue Buttons**:
```java
PlugAndPlaySDK.setReportingIssuesEnabled(false);
```
Use this to prevent users from reporting issues.
[< Back](android.md)

@ -0,0 +1,229 @@
[< Back](ios.md)
## Integrating and Configuring PenNavUI
### Importing PenNavUI
Start by importing the PenNavUI framework into your project:
```swift
import PenNavUI
```
### Conforming to `PenNavInitializationDelegate`
Implement the `PenNavInitializationDelegate` protocol in your view controller to handle initialization events:
```swift
extension ViewController: PenNavInitializationDelegate {
func onPenNavSuccess() {
// Handle successful initialization
}
func onPenNavInitializationError(errorType: PenNavUIError, errorDescription: String) {
// Handle initialization error
}
}
```
### Configuring `PenNavUIManager`
Set up `PenNavUIManager` with the configuration values provided by our Customer Success Team:
```swift
PenNavUIManager.shared
.setClientKey("Your Client Key")
.setClientID("Your Client ID")
.setBaseURL(dataURL: "Your Data URL", positionURL: "Your Position URL")
.setServiceName(dataServiceName: "Your Data Service Name", positionServiceName: "Your Position Service Name")
.build()
```
- Example with more configuration :
```swift
PenNavUIManager.shared
.setClientKey("UGVuZ3VpbklOX1Blb")
.setClientID("ClientA")
.setUsername("UserA")
.setSimulationModeEnabled(isEnable: true)
.setBaseURL(dataURL: "https://temp.client.penguinin.com", positionURL: "https://temp.client.penguinin.com")
.setServiceName(dataServiceName: "api", positionServiceName: "pe")
.setIsShowUserName(false)
.setEnableReportIssue(enable: false)
.setLanguage("en")
.build()
```
### Presenting the Map
After successful initialization, present the map by calling:
```swift
PenNavUIManager.shared.present(root: self, view: view)
```
Ensure the `onPenNavSuccess` method includes this call:
```swift
extension ViewController: PenNavInitializationDelegate {
func onPenNavSuccess() {
PenNavUIManager.shared.present(root: self, view: view)
}
func onPenNavInitializationError(errorType: PenNavUIError, errorDescription: String) {
// Handle initialization error
}
}
```
### Configuring the Location Delegate
To get notified when the user is off campus, conform to the `PILocationDelegate` protocol:
```swift
extension ViewController: PILocationDelegate {
func onLocationOffCampus(location: CLLocationCoordinate2D) {
// Handle user location being off campus
}
}
```
Set the `locationDelegate` of `PenNavUIManager`:
```swift
PenNavUIManager.shared.locationDelegate = self
```
### Configuring the Events Delegate
To handle map dismissal events, conform to the `PIEventsDelegate` protocol:
```swift
extension ViewController: PIEventsDelegate {
func onPenNavUIDismiss() {
// Handle map dismissal
}
}
```
Set the `eventsDelegate` of `PenNavUIManager`:
```swift
PenNavUIManager.shared.eventsDelegate = self
```
### Reporting Issues
Enable issue reporting and handle it using the `PIEventsDelegate` protocol:
```swift
PenNavUIManager.shared.setEnableReportIssue(enable: true)
extension ViewController: PIEventsDelegate {
func onReportIssue(_ issue: PenNavUI.IssueType) {
// Handle issue reporting
Instabug.show()
}
}
```
Set the `eventsDelegate` of `PenNavUIManager`:
```swift
PenNavUIManager.shared.eventsDelegate = self
```
### Navigating to Places
- **Using Reference IDs:**
Navigate to a place using its reference ID:
```swift
PenNavUIManager.shared.navigate(to: "referenceID", completion: { success, error in
// Handle navigation result
})
```
- **Using Deep Links:**
Configure deep linking to share places:
```swift
PenNavUIManager.shared.setDeepLinkScheme("app://", deepLinkDomain: "www.penguinin.com")
PenNavUIManager.shared.setDeepLinkData(data: "YourDeepLinkData")
```
### Simulating User Location
Enable simulation mode for testing purposes:
```swift
PenNavUIManager.shared
.setClientKey("Your Client Key")
.setClientID("Your Client ID")
.setBaseURL(dataURL: "Your Data URL", positionURL: "Your Position URL")
.setServiceName(dataServiceName: "Your Data Service Name", positionServiceName: "Your Position Service Name")
.setSimulationModeEnabled(isEnable: true)
.setUsername("Your Username")
.build()
```
### Dismissing the PenNav SDK
When the PenNav SDK is no longer needed, dismiss it to free up resources:
```swift
PenNavUIManager.shared.dismiss()
```
### Deprecated Methods
Avoid using the following deprecated methods:
- `setOutdoorEnable(isEnable:)`
- `setStepDetectionEnable(isEnable:)`
- `setTransitionEnable(isEnable:)`
### Handling Map Initialization Errors
Here are common errors and their descriptions:
| **Error** | **Description** |
|----------------------------------|------------------------------------------------------------------------|
| Missing Base URL | Specify a valid base URL. |
| Missing Data Service Name | Provide the required data service name. |
| Missing Position Service Name | Provide the required position service name. |
| Missing Client ID | Ensure a valid client ID is provided. |
| Invalid Client Key | Verify and provide a valid client key. |
| Missing Root Controller | Ensure a valid root controller is provided. |
| Missing View Container | Provide a valid view container. |
| Unauthorized | Check your authorization for the requested action. |
| Loading Data Error | Retry loading data. |
| OS Not Supported | Ensure the operating system is supported. |
| No Internet Connection | Verify your internet connection. |
| Sensors Initialization Error | Check sensor settings and retry. |
| Permissions Not Granted | Grant all necessary permissions. |
| Location Permission Not Granted | Grant location permission. |
| Bluetooth Permission Not Granted | Grant Bluetooth permission. |
| Location Services Turned Off | Enable location services. |
| Bluetooth Turned Off | Enable Bluetooth. |
### User Guide for the Demo App
Before installing and running the Demo App, configure `PenNavConfigurations.plist` with the values provided by our Customer Success Team:
| **Key** | **Value** |
|----------------------------|-----------------------------------|
| ClientKey | Provided by the Customer Success Team |
| ClientId | Provided by the Customer Success Team |
| DataUrl | Provided by the Customer Success Team |
| PositionUrl | Provided by the Customer Success Team |
| DataServiceName | Provided by the Customer Success Team |
| PositionServiceName | Provided by the Customer Success Team |
---
[< Back](README-ios.md)

@ -0,0 +1,77 @@
# Errors
* [Missing SDK Configuration](#missing-sdk-configuration)
* [Invalid SDK Configuration](#invalid-sdk-configuration)
* [OS not supported](#os-not-supported)
* [Signal Lost](#signal-lost)
* [Sensors Initial Error](#sensors-initial-error)
* [Loading Data Error](#loading-data-error)
* [Default Venue Not Found](#default-venue-not-found)
* [Default Floor Not Found](#default-floor-not-found)
* [SDK Response Interface is null value](#sdk-response-interface-is-null-value)
* [SDK Configuration is null value](#sdk-configuration-is-null-value)
* [SDK Configuration Error](#sdk-configuration-error)
* [Bluetooth Permissions Not Granted](#bluetooth-permissions-not-granted)
* [Bluetooth Turned Off](#bluetooth-turned-off)
* [Location Turned Off](#location-turned-off)
## Missing SDK Configuration
Check if you set `Client Key`, `Client ID`, `Data URL`, `Position URL`, `Data Service Name`, and `Position Service Name`
## Invalid SDK Configuration
Check if `Client Key`, `Client ID`, `Data URL`, `Position URL`, `Data Service Name`, and `Position Service Name` values match the values provided by our Customer Success Team
## OS not supported
Check if the software version on your device is Android 6.0 or later
minimum os supported is 23
## Signal Lost
Disconnected from server
## Sensors Initial Error
One or more of your device's sensors is failing to communicate
Error while registering and starting sensors (Accelerometer, Magnetometer, Gyro, Orientation, Barometer, Pedometer)
## Loading Data Error
Error while loading data (Venues, Floors, Edges and Settings)
## Default Venue Not Found
Error while preparing outdoor data
## Default Floor Not Found
Error while preparing outdoor data
## SDK Response Interface is null value
Check if you implemented the `PenNavUIDelegate` interface
## SDK Configuration is null value
you have to setup the configuration
[more about configuration ](configration.md)
## SDK Configuration Error
Wrong data provided by configuration
may one of the data is null or empty string
## Bluetooth Permissions Not Granted
Ensure that Bluetooth access has been granted
## Bluetooth Turned Off
Check if Bluetooth is turned on
## Location Turned Off
Check if Location is turned on

@ -0,0 +1,26 @@
# setBaseUrl(dataServerUrl, positionServerUrl)
This function is used to set the server IP or URL for the services required by the P&P module.
usually you will receive the following :
API : https://dev.penguinin.com:9090/api
PE : https://dev.penguinin.com:9090/pe
The URL consists of two parts: the base URL and the service name. The base URL is the first part of the URL, and it specifies the server or hostname. The service name is the second part of the URL, and it specifies the specific service that is being accessed."
For example, in the following URL:
https://dev.penguinin.com:9090/api
The base URL is https://dev.penguinin.com:9090
The service name is api
In this configuration you will pass the first part of the URL which is the server IP
```java
setBaseUrl(https://dev.penguinin.com:9090, https://dev.penguinin.com:9090)
```

@ -0,0 +1,15 @@
# setClientData(clientID, clientKey)
The client identifiers are unique identifiers that are provided by the PenguinIN team. It is used to access the P&P module functionality. With these credentials, clients are able to utilize the features and capabilities of the P&P module.
You will receive
1. clientID
2. clientKey
The clientID and clientKey should be kept confidential and should not be shared with unauthorized parties.
```java
setClientData(clientID, clientKey)
```

@ -0,0 +1,11 @@
# setCustomizeColor
The P&P module offers the ability to customize the colors of certain internal components through a configuration option. This allows users to alter the appearance of the UI to suit their preferences or match their organization's branding.
It is important to note that the default color for the P&P module is #2DA0B0.
> You need to pass the color in hex code
```java
setCustomizeColor(hexCode)
```

@ -0,0 +1,20 @@
# setDeepLinkData
The setDeepLinkData() method allows the passing of deep link data to be displayed on the map. This data is typically in the form of a hashed base64 string. When this method is called with the appropriate deep link data, it will be displayed on the map when it is initialized or already open.
**Parameters**
deepLinkData: A string containing the hashed base64 data to be passed to the map for display. This could include shared locations or points of interest.
- An example deep link including data for display on the map could be: "app://www.demo.com/MiwxLDEwCw5MTEuNDMyNTYsMzUuODY1NjUyMTA3NDQzMTI1LDMxLjk4MjU3MDM3MjQ1"
The data to be displayed on the map would be the last segment of the deep link:
"MiwxLDEwCw5MTEuNDMyNTYsMzUuODY1NjUyMTA3NDQzMTI1LDMxLjk4MjU3MDM3MjQ1"
Example :
```java
setDeepLinkData("MiwxLDEwCw5MTEuNDMyNTYsMzUuODY1NjUyMTA3NDQzMTI1LDMxLjk4MjU3MDM3MjQ1");
```

@ -0,0 +1,39 @@
# setDeepLinkSchema
The setDeepLinkSchema() method allows the specification of a deep link schema for shared locations and points of interest. This is an optional method, and if not provided, the shared location or POI will not be active.
**Parameters**
deepLinkSchema: A string containing the desired deep link schema, such as app://www.demo.com.
## Update AndroidManifest.xml
The \<data> element in the intent-filter specifies the host and scheme for the deep link.
The **android:host** attribute is set to **@string/deeplinkHost**, which refers to the deep link host saved in the <u>**strings.xml**</u> file.
The **android:scheme** attribute is set to **@string/deeplinkSchema**, which refers to the deep link schema saved in the <u>**strings.xml**</u> file.
This allows the app to respond to deep links with the specified host and schema and handle them with the DeepLinkActivity.
It is important to ensure that the host and schema are saved correctly in the strings.xml file and that the correct references are used in the \<data> element of the intent-filter.
```java
<activity
android:name=".Activity">
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
<data
android:host="@string/deeplinkHost"
android:scheme="@string/deeplinkSchema" />
</intent-filter>
</activity>
```
>Note
>- It is recommended to save the deep link host and schema in the strings.xml file for future reference.
>- The deep link schema should be provided in the correct format and adhere to the proper syntax for deep links.
>- The use of this method is optional and may not be necessary in all cases. if not provided, the shared location or Shared POI will not be actived.
```java
setDeepLinkSchema("app://www.demo.com")
```

@ -0,0 +1,20 @@
# setLanguageID
TThis function allows you to select a language code using the predefined 'Languages' enum.
The default language is English ('Languages.en'), but the function also supports Arabic ('Languages.ar').
Example usage:
```java
setLanguageID(Languages.ar); // sets the language to Arabic
```
```java
setLanguageID(Languages.en); // sets the language to English
```
```java
setLanguageID(languageCode)
```
The default language of the P&P module is English.

@ -0,0 +1,23 @@
# setServiceName(dataServiceName,positionServiceName)
This used to configure the server IP or URL for the services needed by the P&P module
Usually you will receive the following :
API : https://dev.penguinin.com:9090/api
PE : https://dev.penguinin.com:9090/pe
The URL consists of two parts: the base URL and the service name. The base URL is the first part of the URL, and it specifies the server or hostname. The service name is the second part of the URL, and it specifies the specific service that is being accessed.
For example, in the following URL:
https://dev.penguinin.com:9090/api
The base URL is https://dev.penguinin.com:9090
The service name is api
```java
setServiceName(api, pe)
```

@ -0,0 +1,12 @@
# setSimulationModeEnabled
If the developer is not on the site and would like to test the P&P module, we have implemented a simulation mode that allows them to open the app with a predefined scenario. This feature is intended to ease the development process and enable the developer to test the app without being on the site.
> Important note :
>
> You will recieve a list of the predefined scenarios , when simulation mode enabled the
> scenario name must be passed into username configration
```java
setSimulationModeEnabled(isSimulation)
```

@ -0,0 +1,14 @@
# setUserName
In this configuration, the app user identifier is the required parameter. This identifier is used to identify the user of the app and is necessary for the proper functioning of the app.
> Important notes :
>
> 1. This identifier must be unique mean that it's not allowed > for two devices to login tp P&P using same username
>
> >Violating this instruction will affect the positioning experience.
```java
setUserName(name)
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

34
ios/.gitignore vendored

@ -0,0 +1,34 @@
**/dgph
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>12.0</string>
</dict>
</plist>

@ -0,0 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"

@ -0,0 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>AvailableLibraries</key>
<array>
<dict>
<key>BinaryPath</key>
<string>PenNavUI.framework/PenNavUI</string>
<key>LibraryIdentifier</key>
<string>ios-arm64_x86_64-simulator</string>
<key>LibraryPath</key>
<string>PenNavUI.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
<string>x86_64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
<key>SupportedPlatformVariant</key>
<string>simulator</string>
</dict>
<dict>
<key>BinaryPath</key>
<string>PenNavUI.framework/PenNavUI</string>
<key>LibraryIdentifier</key>
<string>ios-arm64</string>
<key>LibraryPath</key>
<string>PenNavUI.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
</dict>
</array>
<key>CFBundlePackageType</key>
<string>XFWK</string>
<key>XCFrameworkFormatVersion</key>
<string>1.0</string>
</dict>
</plist>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save