first commit
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
.DS_Store
|
||||||
|
.dart_tool/
|
||||||
|
|
||||||
|
.packages
|
||||||
|
.pub/
|
||||||
|
pubspec.lock
|
||||||
|
|
||||||
|
build/
|
19
.idea/libraries/Dart_SDK.xml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<component name="libraryTable">
|
||||||
|
<library name="Dart SDK">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="file://C:\src\flutter/bin/cache/dart-sdk/lib/async" />
|
||||||
|
<root url="file://C:\src\flutter/bin/cache/dart-sdk/lib/collection" />
|
||||||
|
<root url="file://C:\src\flutter/bin/cache/dart-sdk/lib/convert" />
|
||||||
|
<root url="file://C:\src\flutter/bin/cache/dart-sdk/lib/core" />
|
||||||
|
<root url="file://C:\src\flutter/bin/cache/dart-sdk/lib/developer" />
|
||||||
|
<root url="file://C:\src\flutter/bin/cache/dart-sdk/lib/html" />
|
||||||
|
<root url="file://C:\src\flutter/bin/cache/dart-sdk/lib/io" />
|
||||||
|
<root url="file://C:\src\flutter/bin/cache/dart-sdk/lib/isolate" />
|
||||||
|
<root url="file://C:\src\flutter/bin/cache/dart-sdk/lib/math" />
|
||||||
|
<root url="file://C:\src\flutter/bin/cache/dart-sdk/lib/mirrors" />
|
||||||
|
<root url="file://C:\src\flutter/bin/cache/dart-sdk/lib/typed_data" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES />
|
||||||
|
</library>
|
||||||
|
</component>
|
9
.idea/libraries/Flutter_for_Android.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<component name="libraryTable">
|
||||||
|
<library name="Flutter for Android">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://C:\src\flutter/bin/cache/artifacts/engine/android-arm/flutter.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES />
|
||||||
|
</library>
|
||||||
|
</component>
|
10
.idea/modules.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/flutter_smartconfig.iml" filepath="$PROJECT_DIR$/flutter_smartconfig.iml" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/android/flutter_smartconfig_android.iml" filepath="$PROJECT_DIR$/android/flutter_smartconfig_android.iml" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/example/android/flutter_smartconfig_example_android.iml" filepath="$PROJECT_DIR$/example/android/flutter_smartconfig_example_android.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
6
.idea/runConfigurations/example_lib_main_dart.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="example/lib/main.dart" type="FlutterRunConfigurationType" factoryName="Flutter">
|
||||||
|
<option name="filePath" value="$PROJECT_DIR$/example/lib/main.dart" />
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
45
.idea/workspace.xml
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="FileEditorManager">
|
||||||
|
<leaf>
|
||||||
|
<file leaf-file-name="flutter_smartconfig.dart" pinned="false" current-in-tab="true">
|
||||||
|
<entry file="file://$PROJECT_DIR$/lib/flutter_smartconfig.dart">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file leaf-file-name="main.dart" pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/example/lib/main.dart">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
</leaf>
|
||||||
|
</component>
|
||||||
|
<component name="ToolWindowManager">
|
||||||
|
<editor active="true" />
|
||||||
|
<layout>
|
||||||
|
<window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
|
||||||
|
</layout>
|
||||||
|
</component>
|
||||||
|
<component name="ProjectView">
|
||||||
|
<navigator currentView="ProjectPane" proportions="" version="1">
|
||||||
|
</navigator>
|
||||||
|
<panes>
|
||||||
|
<pane id="ProjectPane">
|
||||||
|
<option name="show-excluded-files" value="false" />
|
||||||
|
</pane>
|
||||||
|
</panes>
|
||||||
|
</component>
|
||||||
|
<component name="PropertiesComponent">
|
||||||
|
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
|
||||||
|
<property name="dart.analysis.tool.window.force.activate" value="true" />
|
||||||
|
<property name="show.migrate.to.gradle.popup" value="false" />
|
||||||
|
</component>
|
||||||
|
</project>
|
10
.metadata
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# 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: 5391447fae6209bb21a89e6a5a6583cac1af9b4b
|
||||||
|
channel: beta
|
||||||
|
|
||||||
|
project_type: plugin
|
3
CHANGELOG.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
## 0.0.1
|
||||||
|
|
||||||
|
* TODO: Describe initial release.
|
14
README.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# flutter_smartconfig
|
||||||
|
|
||||||
|
A new flutter plugin project.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
This project is a starting point for a Flutter
|
||||||
|
[plug-in package](https://flutter.io/developing-packages/),
|
||||||
|
a specialized package that includes platform-specific implementation code for
|
||||||
|
Android and/or iOS.
|
||||||
|
|
||||||
|
For help getting started with Flutter, view our
|
||||||
|
[online documentation](https://flutter.io/docs), which offers tutorials,
|
||||||
|
samples, guidance on mobile development, and a full API reference.
|
8
android/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
*.iml
|
||||||
|
.gradle
|
||||||
|
/local.properties
|
||||||
|
/.idea/workspace.xml
|
||||||
|
/.idea/libraries
|
||||||
|
.DS_Store
|
||||||
|
/build
|
||||||
|
/captures
|
43
android/build.gradle
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
group 'de.mc8051.fluttersmartconfig'
|
||||||
|
version '1.0-SNAPSHOT'
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.android.tools.build:gradle:3.2.1'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.allprojects {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'com.android.library'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 27
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdkVersion 16
|
||||||
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
|
}
|
||||||
|
lintOptions {
|
||||||
|
disable 'InvalidPackage'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects { // Projects
|
||||||
|
gradle.projectsEvaluated {
|
||||||
|
tasks.withType(JavaCompile) {
|
||||||
|
options.encoding = 'UTF-8'
|
||||||
|
options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
android/gradle.properties
Normal file
@ -0,0 +1 @@
|
|||||||
|
org.gradle.jvmargs=-Xmx1536M
|
1
android/settings.gradle
Normal file
@ -0,0 +1 @@
|
|||||||
|
rootProject.name = 'flutter_smartconfig'
|
9
android/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="de.mc8051.fluttersmartconfig">
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||||
|
</manifest>
|
@ -0,0 +1,51 @@
|
|||||||
|
package com.espressif.iot.esptouch;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
public class EsptouchResult implements IEsptouchResult {
|
||||||
|
|
||||||
|
private final boolean mIsSuc;
|
||||||
|
private final String mBssid;
|
||||||
|
private final InetAddress mInetAddress;
|
||||||
|
private AtomicBoolean mIsCancelled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor of EsptouchResult
|
||||||
|
*
|
||||||
|
* @param isSuc whether the esptouch task is executed suc
|
||||||
|
* @param bssid the device's bssid
|
||||||
|
* @param inetAddress the device's ip address
|
||||||
|
*/
|
||||||
|
public EsptouchResult(boolean isSuc, String bssid, InetAddress inetAddress) {
|
||||||
|
this.mIsSuc = isSuc;
|
||||||
|
this.mBssid = bssid;
|
||||||
|
this.mInetAddress = inetAddress;
|
||||||
|
this.mIsCancelled = new AtomicBoolean(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSuc() {
|
||||||
|
return this.mIsSuc;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getBssid() {
|
||||||
|
return this.mBssid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return mIsCancelled.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsCancelled(boolean isCancelled) {
|
||||||
|
this.mIsCancelled.set(isCancelled);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InetAddress getInetAddress() {
|
||||||
|
return this.mInetAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,114 @@
|
|||||||
|
package com.espressif.iot.esptouch;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import com.espressif.iot.esptouch.protocol.TouchData;
|
||||||
|
import com.espressif.iot.esptouch.task.EsptouchTaskParameter;
|
||||||
|
import com.espressif.iot.esptouch.task.__EsptouchTask;
|
||||||
|
import com.espressif.iot.esptouch.util.ByteUtil;
|
||||||
|
import com.espressif.iot.esptouch.util.EspAES;
|
||||||
|
import com.espressif.iot.esptouch.util.EspNetUtil;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class EsptouchTask implements IEsptouchTask {
|
||||||
|
public __EsptouchTask _mEsptouchTask;
|
||||||
|
private EsptouchTaskParameter _mParameter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor of EsptouchTask
|
||||||
|
*
|
||||||
|
* @param apSsid the Ap's ssid
|
||||||
|
* @param apBssid the Ap's bssid
|
||||||
|
* @param apPassword the Ap's password
|
||||||
|
* @param context the Context of the Application
|
||||||
|
*/
|
||||||
|
public EsptouchTask(String apSsid, String apBssid, String apPassword, Context context) {
|
||||||
|
this(apSsid, apBssid, apPassword, null, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor of EsptouchTask
|
||||||
|
*
|
||||||
|
* @param apSsid the Ap's ssid
|
||||||
|
* @param apBssid the Ap's bssid
|
||||||
|
* @param apPassword the Ap's password
|
||||||
|
* @param espAES AES secret key
|
||||||
|
* @param context the Context of the Application
|
||||||
|
*/
|
||||||
|
public EsptouchTask(String apSsid, String apBssid, String apPassword, EspAES espAES, Context context) {
|
||||||
|
if (TextUtils.isEmpty(apSsid)) {
|
||||||
|
throw new NullPointerException("SSID can't be empty");
|
||||||
|
}
|
||||||
|
if (TextUtils.isEmpty(apBssid)) {
|
||||||
|
throw new NullPointerException("BSSID can't be empty");
|
||||||
|
}
|
||||||
|
if (apPassword == null) {
|
||||||
|
apPassword = "";
|
||||||
|
}
|
||||||
|
TouchData ssid = new TouchData(apSsid);
|
||||||
|
TouchData bssid = new TouchData(EspNetUtil.parseBssid2bytes(apBssid));
|
||||||
|
TouchData password = new TouchData(apPassword);
|
||||||
|
init(context, ssid, bssid, password, espAES);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EsptouchTask(byte[] apSsid, byte[] apBssid, byte[] apPassword, Context context) {
|
||||||
|
this(apSsid, apBssid, apPassword, null, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EsptouchTask(byte[] apSsid, byte[] apBssid, byte[] apPassword, EspAES espAES, Context context) {
|
||||||
|
if (apSsid == null || apSsid.length == 0) {
|
||||||
|
throw new NullPointerException("SSID can't be empty");
|
||||||
|
}
|
||||||
|
if (apBssid == null || apBssid.length == 0) {
|
||||||
|
throw new NullPointerException("BSSID can't be empty");
|
||||||
|
}
|
||||||
|
if (apPassword == null) {
|
||||||
|
apPassword = new byte[0];
|
||||||
|
}
|
||||||
|
TouchData ssid = new TouchData(apSsid);
|
||||||
|
TouchData bssid = new TouchData(apBssid);
|
||||||
|
TouchData password = new TouchData(apPassword);
|
||||||
|
init(context, ssid, bssid, password, espAES);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init(Context context, TouchData ssid, TouchData bssid, TouchData password, EspAES aes) {
|
||||||
|
_mParameter = new EsptouchTaskParameter();
|
||||||
|
_mEsptouchTask = new __EsptouchTask(context, ssid, bssid, password, aes, _mParameter, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void interrupt() {
|
||||||
|
_mEsptouchTask.interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IEsptouchResult executeForResult() throws RuntimeException {
|
||||||
|
return _mEsptouchTask.executeForResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return _mEsptouchTask.isCancelled();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<IEsptouchResult> executeForResults(int expectTaskResultCount)
|
||||||
|
throws RuntimeException {
|
||||||
|
if (expectTaskResultCount <= 0) {
|
||||||
|
expectTaskResultCount = Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
return _mEsptouchTask.executeForResults(expectTaskResultCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEsptouchListener(IEsptouchListener esptouchListener) {
|
||||||
|
_mEsptouchTask.setEsptouchListener(esptouchListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPackageBroadcast(boolean broadcast) {
|
||||||
|
_mParameter.setBroadcast(broadcast);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.espressif.iot.esptouch;
|
||||||
|
|
||||||
|
public interface IEsptouchListener {
|
||||||
|
/**
|
||||||
|
* when new esptouch result is added, the listener will call
|
||||||
|
* onEsptouchResultAdded callback
|
||||||
|
*
|
||||||
|
* @param result the Esptouch result
|
||||||
|
*/
|
||||||
|
void onEsptouchResultAdded(IEsptouchResult result);
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.espressif.iot.esptouch;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
|
||||||
|
public interface IEsptouchResult {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check whether the esptouch task is executed suc
|
||||||
|
*
|
||||||
|
* @return whether the esptouch task is executed suc
|
||||||
|
*/
|
||||||
|
boolean isSuc();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the device's bssid
|
||||||
|
*
|
||||||
|
* @return the device's bssid
|
||||||
|
*/
|
||||||
|
String getBssid();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check whether the esptouch task is cancelled by user
|
||||||
|
*
|
||||||
|
* @return whether the esptouch task is cancelled by user
|
||||||
|
*/
|
||||||
|
boolean isCancelled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the ip address of the device
|
||||||
|
*
|
||||||
|
* @return the ip device of the device
|
||||||
|
*/
|
||||||
|
InetAddress getInetAddress();
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
package com.espressif.iot.esptouch;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface IEsptouchTask {
|
||||||
|
String ESPTOUCH_VERSION = "v0.3.7.0";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set the esptouch listener, when one device is connected to the Ap, it will be called back
|
||||||
|
*
|
||||||
|
* @param esptouchListener when one device is connected to the Ap, it will be called back
|
||||||
|
*/
|
||||||
|
void setEsptouchListener(IEsptouchListener esptouchListener);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interrupt the Esptouch Task when User tap back or close the Application.
|
||||||
|
*/
|
||||||
|
void interrupt();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: !!!Don't call the task at UI Main Thread or RuntimeException will
|
||||||
|
* be thrown Execute the Esptouch Task and return the result
|
||||||
|
* <p>
|
||||||
|
* Smart Config v2.4 support the API
|
||||||
|
*
|
||||||
|
* @return the IEsptouchResult
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
IEsptouchResult executeForResult() throws RuntimeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: !!!Don't call the task at UI Main Thread or RuntimeException will
|
||||||
|
* be thrown Execute the Esptouch Task and return the result
|
||||||
|
* <p>
|
||||||
|
* Smart Config v2.4 support the API
|
||||||
|
* <p>
|
||||||
|
* It will be blocked until the client receive result count >= expectTaskResultCount.
|
||||||
|
* If it fail, it will return one fail result will be returned in the list.
|
||||||
|
* If it is cancelled while executing,
|
||||||
|
* if it has received some results, all of them will be returned in the list.
|
||||||
|
* if it hasn't received any results, one cancel result will be returned in the list.
|
||||||
|
*
|
||||||
|
* @param expectTaskResultCount the expect result count(if expectTaskResultCount <= 0,
|
||||||
|
* expectTaskResultCount = Integer.MAX_VALUE)
|
||||||
|
* @return the list of IEsptouchResult
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
List<IEsptouchResult> executeForResults(int expectTaskResultCount) throws RuntimeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check whether the task is cancelled by user
|
||||||
|
*
|
||||||
|
* @return whether the task is cancelled by user
|
||||||
|
*/
|
||||||
|
boolean isCancelled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set broadcast or multicast when post config info
|
||||||
|
*
|
||||||
|
* @param broadcast true is broadcast, false is multicast
|
||||||
|
*/
|
||||||
|
void setPackageBroadcast(boolean broadcast);
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
package com.espressif.iot.esptouch.protocol;
|
||||||
|
|
||||||
|
import com.espressif.iot.esptouch.task.ICodeData;
|
||||||
|
import com.espressif.iot.esptouch.util.ByteUtil;
|
||||||
|
import com.espressif.iot.esptouch.util.CRC8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* one data format:(data code should have 2 to 65 data)
|
||||||
|
* <p>
|
||||||
|
* control byte high 4 bits low 4 bits
|
||||||
|
* 1st 9bits: 0x0 crc(high) data(high)
|
||||||
|
* 2nd 9bits: 0x1 sequence header
|
||||||
|
* 3rd 9bits: 0x0 crc(low) data(low)
|
||||||
|
* <p>
|
||||||
|
* sequence header: 0,1,2,...
|
||||||
|
*
|
||||||
|
* @author afunx
|
||||||
|
*/
|
||||||
|
public class DataCode implements ICodeData {
|
||||||
|
|
||||||
|
public static final int DATA_CODE_LEN = 6;
|
||||||
|
|
||||||
|
private static final int INDEX_MAX = 127;
|
||||||
|
|
||||||
|
private final byte mSeqHeader;
|
||||||
|
private final byte mDataHigh;
|
||||||
|
private final byte mDataLow;
|
||||||
|
// the crc here means the crc of the data and sequence header be transformed
|
||||||
|
// it is calculated by index and data to be transformed
|
||||||
|
private final byte mCrcHigh;
|
||||||
|
private final byte mCrcLow;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor of DataCode
|
||||||
|
*
|
||||||
|
* @param u8 the character to be transformed
|
||||||
|
* @param index the index of the char
|
||||||
|
*/
|
||||||
|
public DataCode(char u8, int index) {
|
||||||
|
if (index > INDEX_MAX) {
|
||||||
|
throw new RuntimeException("index > INDEX_MAX");
|
||||||
|
}
|
||||||
|
byte[] dataBytes = ByteUtil.splitUint8To2bytes(u8);
|
||||||
|
mDataHigh = dataBytes[0];
|
||||||
|
mDataLow = dataBytes[1];
|
||||||
|
CRC8 crc8 = new CRC8();
|
||||||
|
crc8.update(ByteUtil.convertUint8toByte(u8));
|
||||||
|
crc8.update(index);
|
||||||
|
byte[] crcBytes = ByteUtil.splitUint8To2bytes((char) crc8.getValue());
|
||||||
|
mCrcHigh = crcBytes[0];
|
||||||
|
mCrcLow = crcBytes[1];
|
||||||
|
mSeqHeader = (byte) index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getBytes() {
|
||||||
|
byte[] dataBytes = new byte[DATA_CODE_LEN];
|
||||||
|
dataBytes[0] = 0x00;
|
||||||
|
dataBytes[1] = ByteUtil.combine2bytesToOne(mCrcHigh, mDataHigh);
|
||||||
|
dataBytes[2] = 0x01;
|
||||||
|
dataBytes[3] = mSeqHeader;
|
||||||
|
dataBytes[4] = 0x00;
|
||||||
|
dataBytes[5] = ByteUtil.combine2bytesToOne(mCrcLow, mDataLow);
|
||||||
|
return dataBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
byte[] dataBytes = getBytes();
|
||||||
|
for (int i = 0; i < DATA_CODE_LEN; i++) {
|
||||||
|
String hexString = ByteUtil.convertByte2HexString(dataBytes[i]);
|
||||||
|
sb.append("0x");
|
||||||
|
if (hexString.length() == 1) {
|
||||||
|
sb.append("0");
|
||||||
|
}
|
||||||
|
sb.append(hexString).append(" ");
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char[] getU8s() {
|
||||||
|
throw new RuntimeException("DataCode don't support getU8s()");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,157 @@
|
|||||||
|
package com.espressif.iot.esptouch.protocol;
|
||||||
|
|
||||||
|
import com.espressif.iot.esptouch.task.ICodeData;
|
||||||
|
import com.espressif.iot.esptouch.util.ByteUtil;
|
||||||
|
import com.espressif.iot.esptouch.util.CRC8;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
public class DatumCode implements ICodeData {
|
||||||
|
|
||||||
|
// define by the Esptouch protocol, all of the datum code should add 1 at last to prevent 0
|
||||||
|
private static final int EXTRA_LEN = 40;
|
||||||
|
private static final int EXTRA_HEAD_LEN = 5;
|
||||||
|
|
||||||
|
private final LinkedList<DataCode> mDataCodes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor of DatumCode
|
||||||
|
*
|
||||||
|
* @param apSsid the Ap's ssid
|
||||||
|
* @param apBssid the Ap's bssid
|
||||||
|
* @param apPassword the Ap's password
|
||||||
|
* @param ipAddress the ip address of the phone or pad
|
||||||
|
* @param isSsidHiden whether the Ap's ssid is hidden
|
||||||
|
*/
|
||||||
|
public DatumCode(byte[] apSsid, byte[] apBssid, byte[] apPassword,
|
||||||
|
InetAddress ipAddress, boolean isSsidHiden) {
|
||||||
|
// Data = total len(1 byte) + apPwd len(1 byte) + SSID CRC(1 byte) +
|
||||||
|
// BSSID CRC(1 byte) + TOTAL XOR(1 byte)+ ipAddress(4 byte) + apPwd + apSsid apPwdLen <=
|
||||||
|
// 105 at the moment
|
||||||
|
|
||||||
|
// total xor
|
||||||
|
char totalXor = 0;
|
||||||
|
|
||||||
|
char apPwdLen = (char) apPassword.length;
|
||||||
|
CRC8 crc = new CRC8();
|
||||||
|
crc.update(apSsid);
|
||||||
|
char apSsidCrc = (char) crc.getValue();
|
||||||
|
|
||||||
|
crc.reset();
|
||||||
|
crc.update(apBssid);
|
||||||
|
char apBssidCrc = (char) crc.getValue();
|
||||||
|
|
||||||
|
char apSsidLen = (char) apSsid.length;
|
||||||
|
// hostname parse
|
||||||
|
String ipAddrStrs[] = ipAddress.getHostAddress().split("\\.");
|
||||||
|
int ipLen = ipAddrStrs.length;
|
||||||
|
|
||||||
|
char ipAddrChars[] = new char[ipLen];
|
||||||
|
// only support ipv4 at the moment
|
||||||
|
for (int i = 0; i < ipLen; ++i) {
|
||||||
|
ipAddrChars[i] = (char) Integer.parseInt(ipAddrStrs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
char _totalLen = (char) (EXTRA_HEAD_LEN + ipLen + apPwdLen + apSsidLen);
|
||||||
|
char totalLen = isSsidHiden ? (char) (EXTRA_HEAD_LEN + ipLen + apPwdLen + apSsidLen)
|
||||||
|
: (char) (EXTRA_HEAD_LEN + ipLen + apPwdLen);
|
||||||
|
|
||||||
|
// build data codes
|
||||||
|
mDataCodes = new LinkedList<>();
|
||||||
|
mDataCodes.add(new DataCode(_totalLen, 0));
|
||||||
|
totalXor ^= _totalLen;
|
||||||
|
mDataCodes.add(new DataCode(apPwdLen, 1));
|
||||||
|
totalXor ^= apPwdLen;
|
||||||
|
mDataCodes.add(new DataCode(apSsidCrc, 2));
|
||||||
|
totalXor ^= apSsidCrc;
|
||||||
|
mDataCodes.add(new DataCode(apBssidCrc, 3));
|
||||||
|
totalXor ^= apBssidCrc;
|
||||||
|
// ESPDataCode 4 is null
|
||||||
|
for (int i = 0; i < ipLen; ++i) {
|
||||||
|
mDataCodes.add(new DataCode(ipAddrChars[i], i + EXTRA_HEAD_LEN));
|
||||||
|
totalXor ^= ipAddrChars[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] apPwdBytes = apPassword;
|
||||||
|
char[] apPwdChars = new char[apPwdBytes.length];
|
||||||
|
for (int i = 0; i < apPwdBytes.length; i++) {
|
||||||
|
apPwdChars[i] = ByteUtil.convertByte2Uint8(apPwdBytes[i]);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < apPwdChars.length; i++) {
|
||||||
|
mDataCodes.add(new DataCode(apPwdChars[i], i + EXTRA_HEAD_LEN + ipLen));
|
||||||
|
totalXor ^= apPwdChars[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] apSsidBytes = apSsid;
|
||||||
|
char[] apSsidChars = new char[apSsidBytes.length];
|
||||||
|
// totalXor will xor apSsidChars no matter whether the ssid is hidden
|
||||||
|
for (int i = 0; i < apSsidBytes.length; i++) {
|
||||||
|
apSsidChars[i] = ByteUtil.convertByte2Uint8(apSsidBytes[i]);
|
||||||
|
totalXor ^= apSsidChars[i];
|
||||||
|
}
|
||||||
|
if (isSsidHiden) {
|
||||||
|
for (int i = 0; i < apSsidChars.length; i++) {
|
||||||
|
mDataCodes.add(new DataCode(apSsidChars[i], i + EXTRA_HEAD_LEN + ipLen + apPwdLen));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add total xor last
|
||||||
|
mDataCodes.add(4, new DataCode(totalXor, 4));
|
||||||
|
|
||||||
|
// add bssid
|
||||||
|
int bssidInsertIndex = EXTRA_HEAD_LEN;
|
||||||
|
for (int i = 0; i < apBssid.length; i++) {
|
||||||
|
int index = totalLen + i;
|
||||||
|
char c = ByteUtil.convertByte2Uint8(apBssid[i]);
|
||||||
|
DataCode dc = new DataCode(c, index);
|
||||||
|
if (bssidInsertIndex >= mDataCodes.size()) {
|
||||||
|
mDataCodes.add(dc);
|
||||||
|
} else {
|
||||||
|
mDataCodes.add(bssidInsertIndex, dc);
|
||||||
|
}
|
||||||
|
bssidInsertIndex += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getBytes() {
|
||||||
|
byte[] datumCode = new byte[mDataCodes.size() * DataCode.DATA_CODE_LEN];
|
||||||
|
int index = 0;
|
||||||
|
for (DataCode dc : mDataCodes) {
|
||||||
|
for (byte b : dc.getBytes()) {
|
||||||
|
datumCode[index++] = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return datumCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
byte[] dataBytes = getBytes();
|
||||||
|
for (byte dataByte : dataBytes) {
|
||||||
|
String hexString = ByteUtil.convertByte2HexString(dataByte);
|
||||||
|
sb.append("0x");
|
||||||
|
if (hexString.length() == 1) {
|
||||||
|
sb.append("0");
|
||||||
|
}
|
||||||
|
sb.append(hexString).append(" ");
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char[] getU8s() {
|
||||||
|
byte[] dataBytes = getBytes();
|
||||||
|
int len = dataBytes.length / 2;
|
||||||
|
char[] dataU8s = new char[len];
|
||||||
|
byte high, low;
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
high = dataBytes[i * 2];
|
||||||
|
low = dataBytes[i * 2 + 1];
|
||||||
|
dataU8s[i] = (char) (ByteUtil.combine2bytesToU16(high, low) + EXTRA_LEN);
|
||||||
|
}
|
||||||
|
return dataU8s;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
package com.espressif.iot.esptouch.protocol;
|
||||||
|
|
||||||
|
import com.espressif.iot.esptouch.task.IEsptouchGenerator;
|
||||||
|
import com.espressif.iot.esptouch.util.ByteUtil;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
|
||||||
|
public class EsptouchGenerator implements IEsptouchGenerator {
|
||||||
|
|
||||||
|
private final byte[][] mGcBytes2;
|
||||||
|
private final byte[][] mDcBytes2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor of EsptouchGenerator, it will cost some time(maybe a bit
|
||||||
|
* much)
|
||||||
|
*
|
||||||
|
* @param apSsid the Ap's ssid
|
||||||
|
* @param apBssid the Ap's bssid
|
||||||
|
* @param apPassword the Ap's password
|
||||||
|
* @param inetAddress the phone's or pad's local ip address allocated by Ap
|
||||||
|
* @param isSsidHiden whether the Ap's ssid is hidden
|
||||||
|
*/
|
||||||
|
public EsptouchGenerator(byte[] apSsid, byte[] apBssid, byte[] apPassword,
|
||||||
|
InetAddress inetAddress, boolean isSsidHiden) {
|
||||||
|
// generate guide code
|
||||||
|
GuideCode gc = new GuideCode();
|
||||||
|
char[] gcU81 = gc.getU8s();
|
||||||
|
mGcBytes2 = new byte[gcU81.length][];
|
||||||
|
|
||||||
|
for (int i = 0; i < mGcBytes2.length; i++) {
|
||||||
|
mGcBytes2[i] = ByteUtil.genSpecBytes(gcU81[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate data code
|
||||||
|
DatumCode dc = new DatumCode(apSsid, apBssid, apPassword, inetAddress,
|
||||||
|
isSsidHiden);
|
||||||
|
char[] dcU81 = dc.getU8s();
|
||||||
|
mDcBytes2 = new byte[dcU81.length][];
|
||||||
|
|
||||||
|
for (int i = 0; i < mDcBytes2.length; i++) {
|
||||||
|
mDcBytes2[i] = ByteUtil.genSpecBytes(dcU81[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[][] getGCBytes2() {
|
||||||
|
return mGcBytes2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[][] getDCBytes2() {
|
||||||
|
return mDcBytes2;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
package com.espressif.iot.esptouch.protocol;
|
||||||
|
|
||||||
|
import com.espressif.iot.esptouch.task.ICodeData;
|
||||||
|
import com.espressif.iot.esptouch.util.ByteUtil;
|
||||||
|
|
||||||
|
public class GuideCode implements ICodeData {
|
||||||
|
|
||||||
|
public static final int GUIDE_CODE_LEN = 4;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getBytes() {
|
||||||
|
throw new RuntimeException("DataCode don't support getBytes()");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
char[] dataU8s = getU8s();
|
||||||
|
for (int i = 0; i < GUIDE_CODE_LEN; i++) {
|
||||||
|
String hexString = ByteUtil.convertU8ToHexString(dataU8s[i]);
|
||||||
|
sb.append("0x");
|
||||||
|
if (hexString.length() == 1) {
|
||||||
|
sb.append("0");
|
||||||
|
}
|
||||||
|
sb.append(hexString).append(" ");
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char[] getU8s() {
|
||||||
|
char[] guidesU8s = new char[GUIDE_CODE_LEN];
|
||||||
|
guidesU8s[0] = 515;
|
||||||
|
guidesU8s[1] = 514;
|
||||||
|
guidesU8s[2] = 513;
|
||||||
|
guidesU8s[3] = 512;
|
||||||
|
return guidesU8s;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.espressif.iot.esptouch.protocol;
|
||||||
|
|
||||||
|
import com.espressif.iot.esptouch.util.ByteUtil;
|
||||||
|
|
||||||
|
public class TouchData {
|
||||||
|
private final byte[] mData;
|
||||||
|
|
||||||
|
public TouchData(String string) {
|
||||||
|
mData = ByteUtil.getBytesByString(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TouchData(byte[] data) {
|
||||||
|
if (data == null) {
|
||||||
|
throw new NullPointerException("data can't be null");
|
||||||
|
}
|
||||||
|
mData = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getData() {
|
||||||
|
return mData;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,167 @@
|
|||||||
|
package com.espressif.iot.esptouch.task;
|
||||||
|
|
||||||
|
import com.espressif.iot.esptouch.EsptouchTask;
|
||||||
|
|
||||||
|
public class EsptouchTaskParameter implements IEsptouchTaskParameter {
|
||||||
|
|
||||||
|
private static int _datagramCount = 0;
|
||||||
|
private long mIntervalGuideCodeMillisecond;
|
||||||
|
private long mIntervalDataCodeMillisecond;
|
||||||
|
private long mTimeoutGuideCodeMillisecond;
|
||||||
|
private long mTimeoutDataCodeMillisecond;
|
||||||
|
private int mTotalRepeatTime;
|
||||||
|
private int mEsptouchResultOneLen;
|
||||||
|
private int mEsptouchResultMacLen;
|
||||||
|
private int mEsptouchResultIpLen;
|
||||||
|
private int mEsptouchResultTotalLen;
|
||||||
|
private int mPortListening;
|
||||||
|
private int mTargetPort;
|
||||||
|
private int mWaitUdpReceivingMilliseond;
|
||||||
|
private int mWaitUdpSendingMillisecond;
|
||||||
|
private int mThresholdSucBroadcastCount;
|
||||||
|
private int mExpectTaskResultCount;
|
||||||
|
private boolean mBroadcast = true;
|
||||||
|
|
||||||
|
public EsptouchTaskParameter() {
|
||||||
|
mIntervalGuideCodeMillisecond = 8;
|
||||||
|
mIntervalDataCodeMillisecond = 8;
|
||||||
|
mTimeoutGuideCodeMillisecond = 2000;
|
||||||
|
mTimeoutDataCodeMillisecond = 4000;
|
||||||
|
mTotalRepeatTime = 1;
|
||||||
|
mEsptouchResultOneLen = 1;
|
||||||
|
mEsptouchResultMacLen = 6;
|
||||||
|
mEsptouchResultIpLen = 4;
|
||||||
|
mEsptouchResultTotalLen = 1 + 6 + 4;
|
||||||
|
mPortListening = 18266;
|
||||||
|
mTargetPort = 7001;
|
||||||
|
mWaitUdpReceivingMilliseond = 15000;
|
||||||
|
mWaitUdpSendingMillisecond = 45000;
|
||||||
|
mThresholdSucBroadcastCount = 1;
|
||||||
|
mExpectTaskResultCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the range of the result should be 1-100
|
||||||
|
private static int __getNextDatagramCount() {
|
||||||
|
return 1 + (_datagramCount++) % 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getIntervalGuideCodeMillisecond() {
|
||||||
|
return mIntervalGuideCodeMillisecond;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getIntervalDataCodeMillisecond() {
|
||||||
|
return mIntervalDataCodeMillisecond;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getTimeoutGuideCodeMillisecond() {
|
||||||
|
return mTimeoutGuideCodeMillisecond;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getTimeoutDataCodeMillisecond() {
|
||||||
|
return mTimeoutDataCodeMillisecond;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getTimeoutTotalCodeMillisecond() {
|
||||||
|
return mTimeoutGuideCodeMillisecond + mTimeoutDataCodeMillisecond;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTotalRepeatTime() {
|
||||||
|
return mTotalRepeatTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEsptouchResultOneLen() {
|
||||||
|
return mEsptouchResultOneLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEsptouchResultMacLen() {
|
||||||
|
return mEsptouchResultMacLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEsptouchResultIpLen() {
|
||||||
|
return mEsptouchResultIpLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEsptouchResultTotalLen() {
|
||||||
|
return mEsptouchResultTotalLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPortListening() {
|
||||||
|
return mPortListening;
|
||||||
|
}
|
||||||
|
|
||||||
|
// target hostname is : 234.1.1.1, 234.2.2.2, 234.3.3.3 to 234.100.100.100
|
||||||
|
@Override
|
||||||
|
public String getTargetHostname() {
|
||||||
|
if (mBroadcast) {
|
||||||
|
return "255.255.255.255";
|
||||||
|
} else {
|
||||||
|
int count = __getNextDatagramCount();
|
||||||
|
return "234." + count + "." + count + "." + count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTargetPort() {
|
||||||
|
return mTargetPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWaitUdpReceivingMillisecond() {
|
||||||
|
return mWaitUdpReceivingMilliseond;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWaitUdpSendingMillisecond() {
|
||||||
|
return mWaitUdpSendingMillisecond;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWaitUdpTotalMillisecond() {
|
||||||
|
return mWaitUdpReceivingMilliseond + mWaitUdpSendingMillisecond;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setWaitUdpTotalMillisecond(int waitUdpTotalMillisecond) {
|
||||||
|
if (waitUdpTotalMillisecond < mWaitUdpReceivingMilliseond
|
||||||
|
+ getTimeoutTotalCodeMillisecond()) {
|
||||||
|
// if it happen, even one turn about sending udp broadcast can't be
|
||||||
|
// completed
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"waitUdpTotalMillisecod is invalid, "
|
||||||
|
+ "it is less than mWaitUdpReceivingMilliseond + getTimeoutTotalCodeMillisecond()");
|
||||||
|
}
|
||||||
|
mWaitUdpSendingMillisecond = waitUdpTotalMillisecond
|
||||||
|
- mWaitUdpReceivingMilliseond;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getThresholdSucBroadcastCount() {
|
||||||
|
return mThresholdSucBroadcastCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getExpectTaskResultCount() {
|
||||||
|
return this.mExpectTaskResultCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setExpectTaskResultCount(int expectTaskResultCount) {
|
||||||
|
this.mExpectTaskResultCount = expectTaskResultCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBroadcast(boolean broadcast) {
|
||||||
|
mBroadcast = broadcast;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.espressif.iot.esptouch.task;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the class used to represent some code to be transformed by UDP socket should implement the interface
|
||||||
|
*
|
||||||
|
* @author afunx
|
||||||
|
*/
|
||||||
|
public interface ICodeData {
|
||||||
|
/**
|
||||||
|
* Get the byte[] to be transformed.
|
||||||
|
*
|
||||||
|
* @return the byte[] to be transfromed
|
||||||
|
*/
|
||||||
|
byte[] getBytes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the char[](u8[]) to be transfromed.
|
||||||
|
*
|
||||||
|
* @return the char[](u8) to be transformed
|
||||||
|
*/
|
||||||
|
char[] getU8s();
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package com.espressif.iot.esptouch.task;
|
||||||
|
|
||||||
|
public interface IEsptouchGenerator {
|
||||||
|
/**
|
||||||
|
* Get guide code by the format of byte[][]
|
||||||
|
*
|
||||||
|
* @return guide code by the format of byte[][]
|
||||||
|
*/
|
||||||
|
byte[][] getGCBytes2();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get data code by the format of byte[][]
|
||||||
|
*
|
||||||
|
* @return data code by the format of byte[][]
|
||||||
|
*/
|
||||||
|
byte[][] getDCBytes2();
|
||||||
|
}
|
@ -0,0 +1,156 @@
|
|||||||
|
package com.espressif.iot.esptouch.task;
|
||||||
|
|
||||||
|
public interface IEsptouchTaskParameter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get interval millisecond for guide code(the time between each guide code sending)
|
||||||
|
*
|
||||||
|
* @return interval millisecond for guide code(the time between each guide code sending)
|
||||||
|
*/
|
||||||
|
long getIntervalGuideCodeMillisecond();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get interval millisecond for data code(the time between each data code sending)
|
||||||
|
*
|
||||||
|
* @return interval millisecond for data code(the time between each data code sending)
|
||||||
|
*/
|
||||||
|
long getIntervalDataCodeMillisecond();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get timeout millisecond for guide code(the time how much the guide code sending)
|
||||||
|
*
|
||||||
|
* @return timeout millisecond for guide code(the time how much the guide code sending)
|
||||||
|
*/
|
||||||
|
long getTimeoutGuideCodeMillisecond();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get timeout millisecond for data code(the time how much the data code sending)
|
||||||
|
*
|
||||||
|
* @return timeout millisecond for data code(the time how much the data code sending)
|
||||||
|
*/
|
||||||
|
long getTimeoutDataCodeMillisecond();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get timeout millisecond for total code(guide code and data code altogether)
|
||||||
|
*
|
||||||
|
* @return timeout millisecond for total code(guide code and data code altogether)
|
||||||
|
*/
|
||||||
|
long getTimeoutTotalCodeMillisecond();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get total repeat time for executing esptouch task
|
||||||
|
*
|
||||||
|
* @return total repeat time for executing esptouch task
|
||||||
|
*/
|
||||||
|
int getTotalRepeatTime();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the length of the Esptouch result 1st byte is the total length of ssid and
|
||||||
|
* password, the other 6 bytes are the device's bssid
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get esptouchResult length of one
|
||||||
|
*
|
||||||
|
* @return length of one
|
||||||
|
*/
|
||||||
|
int getEsptouchResultOneLen();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get esptouchResult length of mac
|
||||||
|
*
|
||||||
|
* @return length of mac
|
||||||
|
*/
|
||||||
|
int getEsptouchResultMacLen();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get esptouchResult length of ip
|
||||||
|
*
|
||||||
|
* @return length of ip
|
||||||
|
*/
|
||||||
|
int getEsptouchResultIpLen();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get esptouchResult total length
|
||||||
|
*
|
||||||
|
* @return total length
|
||||||
|
*/
|
||||||
|
int getEsptouchResultTotalLen();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get port for listening(used by server)
|
||||||
|
*
|
||||||
|
* @return port for listening(used by server)
|
||||||
|
*/
|
||||||
|
int getPortListening();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get target hostname
|
||||||
|
*
|
||||||
|
* @return target hostame(used by client)
|
||||||
|
*/
|
||||||
|
String getTargetHostname();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get target port
|
||||||
|
*
|
||||||
|
* @return target port(used by client)
|
||||||
|
*/
|
||||||
|
int getTargetPort();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get millisecond for waiting udp receiving(receiving without sending)
|
||||||
|
*
|
||||||
|
* @return millisecond for waiting udp receiving(receiving without sending)
|
||||||
|
*/
|
||||||
|
int getWaitUdpReceivingMillisecond();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get millisecond for waiting udp sending(sending including receiving)
|
||||||
|
*
|
||||||
|
* @return millisecond for waiting udep sending(sending including receiving)
|
||||||
|
*/
|
||||||
|
int getWaitUdpSendingMillisecond();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get millisecond for waiting udp sending and receiving
|
||||||
|
*
|
||||||
|
* @return millisecond for waiting udp sending and receiving
|
||||||
|
*/
|
||||||
|
int getWaitUdpTotalMillisecond();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set the millisecond for waiting udp sending and receiving
|
||||||
|
*
|
||||||
|
* @param waitUdpTotalMillisecond the millisecond for waiting udp sending and receiving
|
||||||
|
*/
|
||||||
|
void setWaitUdpTotalMillisecond(int waitUdpTotalMillisecond);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the threshold for how many correct broadcast should be received
|
||||||
|
*
|
||||||
|
* @return the threshold for how many correct broadcast should be received
|
||||||
|
*/
|
||||||
|
int getThresholdSucBroadcastCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the count of expect task results
|
||||||
|
*
|
||||||
|
* @return the count of expect task results
|
||||||
|
*/
|
||||||
|
int getExpectTaskResultCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set the count of expect task results
|
||||||
|
*
|
||||||
|
* @param expectTaskResultCount the count of expect task results
|
||||||
|
*/
|
||||||
|
void setExpectTaskResultCount(int expectTaskResultCount);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set broadcast or multicast
|
||||||
|
*
|
||||||
|
* @param broadcast true is broadcast, false is multicast
|
||||||
|
*/
|
||||||
|
void setBroadcast(boolean broadcast);
|
||||||
|
}
|
@ -0,0 +1,355 @@
|
|||||||
|
package com.espressif.iot.esptouch.task;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.espressif.iot.esptouch.EsptouchResult;
|
||||||
|
import com.espressif.iot.esptouch.IEsptouchListener;
|
||||||
|
import com.espressif.iot.esptouch.IEsptouchResult;
|
||||||
|
import com.espressif.iot.esptouch.IEsptouchTask;
|
||||||
|
import com.espressif.iot.esptouch.protocol.EsptouchGenerator;
|
||||||
|
import com.espressif.iot.esptouch.protocol.TouchData;
|
||||||
|
import com.espressif.iot.esptouch.udp.UDPSocketClient;
|
||||||
|
import com.espressif.iot.esptouch.udp.UDPSocketServer;
|
||||||
|
import com.espressif.iot.esptouch.util.ByteUtil;
|
||||||
|
import com.espressif.iot.esptouch.util.EspAES;
|
||||||
|
import com.espressif.iot.esptouch.util.EspNetUtil;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
public class __EsptouchTask implements __IEsptouchTask {
|
||||||
|
/**
|
||||||
|
* one indivisible data contain 3 9bits info
|
||||||
|
*/
|
||||||
|
private static final int ONE_DATA_LEN = 3;
|
||||||
|
|
||||||
|
private static final String TAG = "__EsptouchTask";
|
||||||
|
|
||||||
|
private final UDPSocketClient mSocketClient;
|
||||||
|
private final UDPSocketServer mSocketServer;
|
||||||
|
private final byte[] mApSsid;
|
||||||
|
private final byte[] mApPassword;
|
||||||
|
private final byte[] mApBssid;
|
||||||
|
private final boolean mIsSsidHidden;
|
||||||
|
private final Context mContext;
|
||||||
|
private volatile List<IEsptouchResult> mEsptouchResultList;
|
||||||
|
private volatile boolean mIsSuc = false;
|
||||||
|
private volatile boolean mIsInterrupt = false;
|
||||||
|
private volatile boolean mIsExecuted = false;
|
||||||
|
private AtomicBoolean mIsCancelled;
|
||||||
|
private IEsptouchTaskParameter mParameter;
|
||||||
|
private volatile Map<String, Integer> mBssidTaskSucCountMap;
|
||||||
|
private IEsptouchListener mEsptouchListener;
|
||||||
|
private Thread mTask;
|
||||||
|
|
||||||
|
public __EsptouchTask(Context context, TouchData apSsid, TouchData apBssid, TouchData apPassword, EspAES espAES,
|
||||||
|
IEsptouchTaskParameter parameter, boolean isSsidHidden) {
|
||||||
|
Log.i(TAG, "Welcome Esptouch " + IEsptouchTask.ESPTOUCH_VERSION);
|
||||||
|
mContext = context;
|
||||||
|
if (espAES == null) {
|
||||||
|
mApSsid = apSsid.getData();
|
||||||
|
mApPassword = apPassword.getData();
|
||||||
|
} else {
|
||||||
|
mApSsid = espAES.encrypt(apSsid.getData());
|
||||||
|
mApPassword = espAES.encrypt(apPassword.getData());
|
||||||
|
}
|
||||||
|
mApBssid = apBssid.getData();
|
||||||
|
mIsCancelled = new AtomicBoolean(false);
|
||||||
|
mSocketClient = new UDPSocketClient();
|
||||||
|
mParameter = parameter;
|
||||||
|
mSocketServer = new UDPSocketServer(mParameter.getPortListening(),
|
||||||
|
mParameter.getWaitUdpTotalMillisecond(), context);
|
||||||
|
mIsSsidHidden = isSsidHidden;
|
||||||
|
mEsptouchResultList = new ArrayList<>();
|
||||||
|
mBssidTaskSucCountMap = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void __putEsptouchResult(boolean isSuc, String bssid, InetAddress inetAddress) {
|
||||||
|
synchronized (mEsptouchResultList) {
|
||||||
|
// check whether the result receive enough UDP response
|
||||||
|
boolean isTaskSucCountEnough = false;
|
||||||
|
Integer count = mBssidTaskSucCountMap.get(bssid);
|
||||||
|
if (count == null) {
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
++count;
|
||||||
|
if (__IEsptouchTask.DEBUG) {
|
||||||
|
Log.d(TAG, "__putEsptouchResult(): count = " + count);
|
||||||
|
}
|
||||||
|
mBssidTaskSucCountMap.put(bssid, count);
|
||||||
|
isTaskSucCountEnough = count >= mParameter
|
||||||
|
.getThresholdSucBroadcastCount();
|
||||||
|
if (!isTaskSucCountEnough) {
|
||||||
|
if (__IEsptouchTask.DEBUG) {
|
||||||
|
Log.d(TAG, "__putEsptouchResult(): count = " + count
|
||||||
|
+ ", isn't enough");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// check whether the result is in the mEsptouchResultList already
|
||||||
|
boolean isExist = false;
|
||||||
|
for (IEsptouchResult esptouchResultInList : mEsptouchResultList) {
|
||||||
|
if (esptouchResultInList.getBssid().equals(bssid)) {
|
||||||
|
isExist = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// only add the result who isn't in the mEsptouchResultList
|
||||||
|
if (!isExist) {
|
||||||
|
if (__IEsptouchTask.DEBUG) {
|
||||||
|
Log.d(TAG, "__putEsptouchResult(): put one more result");
|
||||||
|
}
|
||||||
|
final IEsptouchResult esptouchResult = new EsptouchResult(isSuc,
|
||||||
|
bssid, inetAddress);
|
||||||
|
mEsptouchResultList.add(esptouchResult);
|
||||||
|
if (mEsptouchListener != null) {
|
||||||
|
mEsptouchListener.onEsptouchResultAdded(esptouchResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<IEsptouchResult> __getEsptouchResultList() {
|
||||||
|
synchronized (mEsptouchResultList) {
|
||||||
|
if (mEsptouchResultList.isEmpty()) {
|
||||||
|
EsptouchResult esptouchResultFail = new EsptouchResult(false,
|
||||||
|
null, null);
|
||||||
|
esptouchResultFail.setIsCancelled(mIsCancelled.get());
|
||||||
|
mEsptouchResultList.add(esptouchResultFail);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mEsptouchResultList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void __interrupt() {
|
||||||
|
if (!mIsInterrupt) {
|
||||||
|
mIsInterrupt = true;
|
||||||
|
mSocketClient.interrupt();
|
||||||
|
mSocketServer.interrupt();
|
||||||
|
// interrupt the current Thread which is used to wait for udp response
|
||||||
|
if (mTask != null) {
|
||||||
|
mTask.interrupt();
|
||||||
|
mTask = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void interrupt() {
|
||||||
|
if (__IEsptouchTask.DEBUG) {
|
||||||
|
Log.d(TAG, "interrupt()");
|
||||||
|
}
|
||||||
|
mIsCancelled.set(true);
|
||||||
|
__interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void __listenAsyn(final int expectDataLen) {
|
||||||
|
mTask = new Thread() {
|
||||||
|
public void run() {
|
||||||
|
if (__IEsptouchTask.DEBUG) {
|
||||||
|
Log.d(TAG, "__listenAsyn() start");
|
||||||
|
}
|
||||||
|
long startTimestamp = System.currentTimeMillis();
|
||||||
|
// byte[] apSsidAndPassword = ByteUtil.getBytesByString(mApSsid
|
||||||
|
// + mApPassword);
|
||||||
|
byte expectOneByte = (byte) (mApSsid.length + mApPassword.length + 9);
|
||||||
|
if (__IEsptouchTask.DEBUG) {
|
||||||
|
Log.i(TAG, "expectOneByte: " + (0 + expectOneByte));
|
||||||
|
}
|
||||||
|
byte receiveOneByte = -1;
|
||||||
|
byte[] receiveBytes = null;
|
||||||
|
while (mEsptouchResultList.size() < mParameter
|
||||||
|
.getExpectTaskResultCount() && !mIsInterrupt) {
|
||||||
|
receiveBytes = mSocketServer
|
||||||
|
.receiveSpecLenBytes(expectDataLen);
|
||||||
|
if (receiveBytes != null) {
|
||||||
|
receiveOneByte = receiveBytes[0];
|
||||||
|
} else {
|
||||||
|
receiveOneByte = -1;
|
||||||
|
}
|
||||||
|
if (receiveOneByte == expectOneByte) {
|
||||||
|
if (__IEsptouchTask.DEBUG) {
|
||||||
|
Log.i(TAG, "receive correct broadcast");
|
||||||
|
}
|
||||||
|
// change the socket's timeout
|
||||||
|
long consume = System.currentTimeMillis()
|
||||||
|
- startTimestamp;
|
||||||
|
int timeout = (int) (mParameter
|
||||||
|
.getWaitUdpTotalMillisecond() - consume);
|
||||||
|
if (timeout < 0) {
|
||||||
|
if (__IEsptouchTask.DEBUG) {
|
||||||
|
Log.i(TAG, "esptouch timeout");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (__IEsptouchTask.DEBUG) {
|
||||||
|
Log.i(TAG, "mSocketServer's new timeout is "
|
||||||
|
+ timeout + " milliseconds");
|
||||||
|
}
|
||||||
|
mSocketServer.setSoTimeout(timeout);
|
||||||
|
if (__IEsptouchTask.DEBUG) {
|
||||||
|
Log.i(TAG, "receive correct broadcast");
|
||||||
|
}
|
||||||
|
if (receiveBytes != null) {
|
||||||
|
String bssid = ByteUtil.parseBssid(
|
||||||
|
receiveBytes,
|
||||||
|
mParameter.getEsptouchResultOneLen(),
|
||||||
|
mParameter.getEsptouchResultMacLen());
|
||||||
|
InetAddress inetAddress = EspNetUtil
|
||||||
|
.parseInetAddr(
|
||||||
|
receiveBytes,
|
||||||
|
mParameter
|
||||||
|
.getEsptouchResultOneLen()
|
||||||
|
+ mParameter
|
||||||
|
.getEsptouchResultMacLen(),
|
||||||
|
mParameter
|
||||||
|
.getEsptouchResultIpLen());
|
||||||
|
__putEsptouchResult(true, bssid, inetAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (__IEsptouchTask.DEBUG) {
|
||||||
|
Log.i(TAG, "receive rubbish message, just ignore");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mIsSuc = mEsptouchResultList.size() >= mParameter
|
||||||
|
.getExpectTaskResultCount();
|
||||||
|
__EsptouchTask.this.__interrupt();
|
||||||
|
if (__IEsptouchTask.DEBUG) {
|
||||||
|
Log.d(TAG, "__listenAsyn() finish");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mTask.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean __execute(IEsptouchGenerator generator) {
|
||||||
|
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
long currentTime = startTime;
|
||||||
|
long lastTime = currentTime - mParameter.getTimeoutTotalCodeMillisecond();
|
||||||
|
|
||||||
|
byte[][] gcBytes2 = generator.getGCBytes2();
|
||||||
|
byte[][] dcBytes2 = generator.getDCBytes2();
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
while (!mIsInterrupt) {
|
||||||
|
if (currentTime - lastTime >= mParameter.getTimeoutTotalCodeMillisecond()) {
|
||||||
|
if (__IEsptouchTask.DEBUG) {
|
||||||
|
Log.d(TAG, "send gc code ");
|
||||||
|
}
|
||||||
|
// send guide code
|
||||||
|
while (!mIsInterrupt
|
||||||
|
&& System.currentTimeMillis() - currentTime < mParameter
|
||||||
|
.getTimeoutGuideCodeMillisecond()) {
|
||||||
|
mSocketClient.sendData(gcBytes2,
|
||||||
|
mParameter.getTargetHostname(),
|
||||||
|
mParameter.getTargetPort(),
|
||||||
|
mParameter.getIntervalGuideCodeMillisecond());
|
||||||
|
// check whether the udp is send enough time
|
||||||
|
if (System.currentTimeMillis() - startTime > mParameter.getWaitUdpSendingMillisecond()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastTime = currentTime;
|
||||||
|
} else {
|
||||||
|
mSocketClient.sendData(dcBytes2, index, ONE_DATA_LEN,
|
||||||
|
mParameter.getTargetHostname(),
|
||||||
|
mParameter.getTargetPort(),
|
||||||
|
mParameter.getIntervalDataCodeMillisecond());
|
||||||
|
index = (index + ONE_DATA_LEN) % dcBytes2.length;
|
||||||
|
}
|
||||||
|
currentTime = System.currentTimeMillis();
|
||||||
|
// check whether the udp is send enough time
|
||||||
|
if (currentTime - startTime > mParameter.getWaitUdpSendingMillisecond()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mIsSuc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void __checkTaskValid() {
|
||||||
|
// !!!NOTE: the esptouch task could be executed only once
|
||||||
|
if (this.mIsExecuted) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"the Esptouch task could be executed only once");
|
||||||
|
}
|
||||||
|
this.mIsExecuted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IEsptouchResult executeForResult() throws RuntimeException {
|
||||||
|
return executeForResults(1).get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return this.mIsCancelled.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<IEsptouchResult> executeForResults(int expectTaskResultCount)
|
||||||
|
throws RuntimeException {
|
||||||
|
__checkTaskValid();
|
||||||
|
|
||||||
|
mParameter.setExpectTaskResultCount(expectTaskResultCount);
|
||||||
|
|
||||||
|
if (__IEsptouchTask.DEBUG) {
|
||||||
|
Log.d(TAG, "execute()");
|
||||||
|
}
|
||||||
|
if (Looper.myLooper() == Looper.getMainLooper()) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"Don't call the esptouch Task at Main(UI) thread directly.");
|
||||||
|
}
|
||||||
|
InetAddress localInetAddress = EspNetUtil.getLocalInetAddress(mContext);
|
||||||
|
if (__IEsptouchTask.DEBUG) {
|
||||||
|
Log.i(TAG, "localInetAddress: " + localInetAddress);
|
||||||
|
}
|
||||||
|
// generator the esptouch byte[][] to be transformed, which will cost
|
||||||
|
// some time(maybe a bit much)
|
||||||
|
IEsptouchGenerator generator = new EsptouchGenerator(mApSsid, mApBssid,
|
||||||
|
mApPassword, localInetAddress, mIsSsidHidden);
|
||||||
|
// listen the esptouch result asyn
|
||||||
|
__listenAsyn(mParameter.getEsptouchResultTotalLen());
|
||||||
|
boolean isSuc = false;
|
||||||
|
for (int i = 0; i < mParameter.getTotalRepeatTime(); i++) {
|
||||||
|
isSuc = __execute(generator);
|
||||||
|
if (isSuc) {
|
||||||
|
return __getEsptouchResultList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mIsInterrupt) {
|
||||||
|
// wait the udp response without sending udp broadcast
|
||||||
|
try {
|
||||||
|
Thread.sleep(mParameter.getWaitUdpReceivingMillisecond());
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// receive the udp broadcast or the user interrupt the task
|
||||||
|
if (this.mIsSuc) {
|
||||||
|
return __getEsptouchResultList();
|
||||||
|
} else {
|
||||||
|
this.__interrupt();
|
||||||
|
return __getEsptouchResultList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.__interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
return __getEsptouchResultList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEsptouchListener(IEsptouchListener esptouchListener) {
|
||||||
|
mEsptouchListener = esptouchListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
package com.espressif.iot.esptouch.task;
|
||||||
|
|
||||||
|
import com.espressif.iot.esptouch.IEsptouchListener;
|
||||||
|
import com.espressif.iot.esptouch.IEsptouchResult;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IEsptouchTask defined the task of esptouch should offer. INTERVAL here means
|
||||||
|
* the milliseconds of interval of the step. REPEAT here means the repeat times
|
||||||
|
* of the step.
|
||||||
|
*
|
||||||
|
* @author afunx
|
||||||
|
*/
|
||||||
|
public interface __IEsptouchTask {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turn on or off the log.
|
||||||
|
*/
|
||||||
|
static final boolean DEBUG = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set the esptouch listener, when one device is connected to the Ap, it will be called back
|
||||||
|
*
|
||||||
|
* @param esptouchListener when one device is connected to the Ap, it will be called back
|
||||||
|
*/
|
||||||
|
void setEsptouchListener(IEsptouchListener esptouchListener);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interrupt the Esptouch Task when User tap back or close the Application.
|
||||||
|
*/
|
||||||
|
void interrupt();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: !!!Don't call the task at UI Main Thread or RuntimeException will
|
||||||
|
* be thrown Execute the Esptouch Task and return the result
|
||||||
|
*
|
||||||
|
* @return the IEsptouchResult
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
IEsptouchResult executeForResult() throws RuntimeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: !!!Don't call the task at UI Main Thread or RuntimeException will
|
||||||
|
* be thrown Execute the Esptouch Task and return the result
|
||||||
|
*
|
||||||
|
* @param expectTaskResultCount the expect result count(if expectTaskResultCount <= 0,
|
||||||
|
* expectTaskResultCount = Integer.MAX_VALUE)
|
||||||
|
* @return the list of IEsptouchResult
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
List<IEsptouchResult> executeForResults(int expectTaskResultCount) throws RuntimeException;
|
||||||
|
|
||||||
|
boolean isCancelled();
|
||||||
|
}
|
@ -0,0 +1,130 @@
|
|||||||
|
package com.espressif.iot.esptouch.udp;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.espressif.iot.esptouch.task.__IEsptouchTask;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.DatagramPacket;
|
||||||
|
import java.net.DatagramSocket;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this class is used to help send UDP data according to length
|
||||||
|
*
|
||||||
|
* @author afunx
|
||||||
|
*/
|
||||||
|
public class UDPSocketClient {
|
||||||
|
|
||||||
|
private static final String TAG = "UDPSocketClient";
|
||||||
|
private DatagramSocket mSocket;
|
||||||
|
private volatile boolean mIsStop;
|
||||||
|
private volatile boolean mIsClosed;
|
||||||
|
|
||||||
|
public UDPSocketClient() {
|
||||||
|
try {
|
||||||
|
this.mSocket = new DatagramSocket();
|
||||||
|
this.mIsStop = false;
|
||||||
|
this.mIsClosed = false;
|
||||||
|
} catch (SocketException e) {
|
||||||
|
if (__IEsptouchTask.DEBUG) {
|
||||||
|
Log.e(TAG, "SocketException");
|
||||||
|
}
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finalize() throws Throwable {
|
||||||
|
close();
|
||||||
|
super.finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void interrupt() {
|
||||||
|
if (__IEsptouchTask.DEBUG) {
|
||||||
|
Log.i(TAG, "USPSocketClient is interrupt");
|
||||||
|
}
|
||||||
|
this.mIsStop = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* close the UDP socket
|
||||||
|
*/
|
||||||
|
public synchronized void close() {
|
||||||
|
if (!this.mIsClosed) {
|
||||||
|
this.mSocket.close();
|
||||||
|
this.mIsClosed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send the data by UDP
|
||||||
|
*
|
||||||
|
* @param data the data to be sent
|
||||||
|
* @param targetPort the port of target
|
||||||
|
* @param interval the milliseconds to between each UDP sent
|
||||||
|
*/
|
||||||
|
public void sendData(byte[][] data, String targetHostName, int targetPort,
|
||||||
|
long interval) {
|
||||||
|
sendData(data, 0, data.length, targetHostName, targetPort, interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send the data by UDP
|
||||||
|
*
|
||||||
|
* @param data the data to be sent
|
||||||
|
* @param offset the offset which data to be sent
|
||||||
|
* @param count the count of the data
|
||||||
|
* @param targetPort the port of target
|
||||||
|
* @param interval the milliseconds to between each UDP sent
|
||||||
|
*/
|
||||||
|
public void sendData(byte[][] data, int offset, int count,
|
||||||
|
String targetHostName, int targetPort, long interval) {
|
||||||
|
if ((data == null) || (data.length <= 0)) {
|
||||||
|
if (__IEsptouchTask.DEBUG) {
|
||||||
|
Log.e(TAG, "sendData(): data == null or length <= 0");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = offset; !mIsStop && i < offset + count; i++) {
|
||||||
|
if (data[i].length == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
InetAddress targetInetAddress = InetAddress.getByName(targetHostName);
|
||||||
|
DatagramPacket localDatagramPacket = new DatagramPacket(
|
||||||
|
data[i], data[i].length, targetInetAddress, targetPort);
|
||||||
|
this.mSocket.send(localDatagramPacket);
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
if (__IEsptouchTask.DEBUG) {
|
||||||
|
Log.e(TAG, "sendData(): UnknownHostException");
|
||||||
|
}
|
||||||
|
e.printStackTrace();
|
||||||
|
mIsStop = true;
|
||||||
|
break;
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (__IEsptouchTask.DEBUG) {
|
||||||
|
Log.e(TAG, "sendData(): IOException, but just ignore it");
|
||||||
|
}
|
||||||
|
// for the Ap will make some troubles when the phone send too many UDP packets,
|
||||||
|
// but we don't expect the UDP packet received by others, so just ignore it
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Thread.sleep(interval);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
if (__IEsptouchTask.DEBUG) {
|
||||||
|
Log.e(TAG, "sendData is Interrupted");
|
||||||
|
}
|
||||||
|
mIsStop = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mIsStop) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,151 @@
|
|||||||
|
package com.espressif.iot.esptouch.udp;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.wifi.WifiManager;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.DatagramPacket;
|
||||||
|
import java.net.DatagramSocket;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class UDPSocketServer {
|
||||||
|
private static final String TAG = "UDPSocketServer";
|
||||||
|
private final byte[] buffer;
|
||||||
|
private DatagramPacket mReceivePacket;
|
||||||
|
private DatagramSocket mServerSocket;
|
||||||
|
private Context mContext;
|
||||||
|
private WifiManager.MulticastLock mLock;
|
||||||
|
private volatile boolean mIsClosed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor of UDP Socket Server
|
||||||
|
*
|
||||||
|
* @param port the Socket Server port
|
||||||
|
* @param socketTimeout the socket read timeout
|
||||||
|
* @param context the context of the Application
|
||||||
|
*/
|
||||||
|
public UDPSocketServer(int port, int socketTimeout, Context context) {
|
||||||
|
this.mContext = context;
|
||||||
|
this.buffer = new byte[64];
|
||||||
|
this.mReceivePacket = new DatagramPacket(buffer, 64);
|
||||||
|
try {
|
||||||
|
this.mServerSocket = new DatagramSocket(null);
|
||||||
|
this.mServerSocket.setReuseAddress(true);
|
||||||
|
this.mServerSocket.bind(new InetSocketAddress(port));
|
||||||
|
this.mServerSocket.setSoTimeout(socketTimeout);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "IOException");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
this.mIsClosed = false;
|
||||||
|
WifiManager manager = (WifiManager) mContext.getApplicationContext()
|
||||||
|
.getSystemService(Context.WIFI_SERVICE);
|
||||||
|
mLock = manager.createMulticastLock("test wifi");
|
||||||
|
Log.d(TAG, "mServerSocket is created, socket read timeout: "
|
||||||
|
+ socketTimeout + ", port: " + port);
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void acquireLock() {
|
||||||
|
if (mLock != null && !mLock.isHeld()) {
|
||||||
|
mLock.acquire();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void releaseLock() {
|
||||||
|
if (mLock != null && mLock.isHeld()) {
|
||||||
|
try {
|
||||||
|
mLock.release();
|
||||||
|
} catch (Throwable th) {
|
||||||
|
// ignoring this exception, probably wakeLock was already released
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the socket timeout in milliseconds
|
||||||
|
*
|
||||||
|
* @param timeout the timeout in milliseconds or 0 for no timeout.
|
||||||
|
* @return true whether the timeout is set suc
|
||||||
|
*/
|
||||||
|
public boolean setSoTimeout(int timeout) {
|
||||||
|
try {
|
||||||
|
this.mServerSocket.setSoTimeout(timeout);
|
||||||
|
return true;
|
||||||
|
} catch (SocketException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive one byte from the port and convert it into String
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public byte receiveOneByte() {
|
||||||
|
Log.d(TAG, "receiveOneByte() entrance");
|
||||||
|
try {
|
||||||
|
acquireLock();
|
||||||
|
mServerSocket.receive(mReceivePacket);
|
||||||
|
Log.d(TAG, "receive: " + (mReceivePacket.getData()[0]));
|
||||||
|
return mReceivePacket.getData()[0];
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return Byte.MIN_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive specific length bytes from the port and convert it into String
|
||||||
|
* 21,24,-2,52,-102,-93,-60
|
||||||
|
* 15,18,fe,34,9a,a3,c4
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public byte[] receiveSpecLenBytes(int len) {
|
||||||
|
Log.d(TAG, "receiveSpecLenBytes() entrance: len = " + len);
|
||||||
|
try {
|
||||||
|
acquireLock();
|
||||||
|
mServerSocket.receive(mReceivePacket);
|
||||||
|
byte[] recDatas = Arrays.copyOf(mReceivePacket.getData(), mReceivePacket.getLength());
|
||||||
|
Log.d(TAG, "received len : " + recDatas.length);
|
||||||
|
for (int i = 0; i < recDatas.length; i++) {
|
||||||
|
Log.e(TAG, "recDatas[" + i + "]:" + recDatas[i]);
|
||||||
|
}
|
||||||
|
Log.e(TAG, "receiveSpecLenBytes: " + new String(recDatas));
|
||||||
|
if (recDatas.length != len) {
|
||||||
|
Log.w(TAG,
|
||||||
|
"received len is different from specific len, return null");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return recDatas;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void interrupt() {
|
||||||
|
Log.i(TAG, "USPSocketServer is interrupt");
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void close() {
|
||||||
|
if (!this.mIsClosed) {
|
||||||
|
Log.e(TAG, "mServerSocket is closed");
|
||||||
|
mServerSocket.close();
|
||||||
|
releaseLock();
|
||||||
|
this.mIsClosed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finalize() throws Throwable {
|
||||||
|
close();
|
||||||
|
super.finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,323 @@
|
|||||||
|
package com.espressif.iot.esptouch.util;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In Java, it don't support unsigned int, so we use char to replace uint8.
|
||||||
|
* The range of byte is [-128,127], and the range of char is [0,65535].
|
||||||
|
* So the byte could used to store the uint8.
|
||||||
|
* (We assume that the String could be mapped to assic)
|
||||||
|
*
|
||||||
|
* @author afunx
|
||||||
|
*/
|
||||||
|
public class ByteUtil {
|
||||||
|
|
||||||
|
public static final String ESPTOUCH_ENCODING_CHARSET = "UTF-8";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put String to byte[]
|
||||||
|
*
|
||||||
|
* @param destbytes the byte[] of dest
|
||||||
|
* @param srcString the String of src
|
||||||
|
* @param destOffset the offset of byte[]
|
||||||
|
* @param srcOffset the offset of String
|
||||||
|
* @param count the count of dest, and the count of src as well
|
||||||
|
*/
|
||||||
|
public static void putString2bytes(byte[] destbytes, String srcString,
|
||||||
|
int destOffset, int srcOffset, int count) {
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
destbytes[count + i] = srcString.getBytes()[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert uint8 into char( we treat char as uint8)
|
||||||
|
*
|
||||||
|
* @param uint8 the unit8 to be converted
|
||||||
|
* @return the byte of the unint8
|
||||||
|
*/
|
||||||
|
public static byte convertUint8toByte(char uint8) {
|
||||||
|
if (uint8 > Byte.MAX_VALUE - Byte.MIN_VALUE) {
|
||||||
|
throw new RuntimeException("Out of Boundary");
|
||||||
|
}
|
||||||
|
return (byte) uint8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert char into uint8( we treat char as uint8 )
|
||||||
|
*
|
||||||
|
* @param b the byte to be converted
|
||||||
|
* @return the char(uint8)
|
||||||
|
*/
|
||||||
|
public static char convertByte2Uint8(byte b) {
|
||||||
|
// char will be promoted to int for char don't support & operator
|
||||||
|
// & 0xff could make negatvie value to positive
|
||||||
|
return (char) (b & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert byte[] into char[]( we treat char[] as uint8[])
|
||||||
|
*
|
||||||
|
* @param bytes the byte[] to be converted
|
||||||
|
* @return the char[](uint8[])
|
||||||
|
*/
|
||||||
|
public static char[] convertBytes2Uint8s(byte[] bytes) {
|
||||||
|
int len = bytes.length;
|
||||||
|
char[] uint8s = new char[len];
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
uint8s[i] = convertByte2Uint8(bytes[i]);
|
||||||
|
}
|
||||||
|
return uint8s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put byte[] into char[]( we treat char[] as uint8[])
|
||||||
|
*
|
||||||
|
* @param destUint8s the char[](uint8[]) array
|
||||||
|
* @param srcBytes the byte[]
|
||||||
|
* @param destOffset the offset of char[](uint8[])
|
||||||
|
* @param srcOffset the offset of byte[]
|
||||||
|
* @param count the count of dest, and the count of src as well
|
||||||
|
*/
|
||||||
|
public static void putbytes2Uint8s(char[] destUint8s, byte[] srcBytes,
|
||||||
|
int destOffset, int srcOffset, int count) {
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
destUint8s[destOffset + i] = convertByte2Uint8(srcBytes[srcOffset
|
||||||
|
+ i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert byte to Hex String
|
||||||
|
*
|
||||||
|
* @param b the byte to be converted
|
||||||
|
* @return the Hex String
|
||||||
|
*/
|
||||||
|
public static String convertByte2HexString(byte b) {
|
||||||
|
char u8 = convertByte2Uint8(b);
|
||||||
|
return Integer.toHexString(u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert char(uint8) to Hex String
|
||||||
|
*
|
||||||
|
* @param u8 the char(uint8) to be converted
|
||||||
|
* @return the Hex String
|
||||||
|
*/
|
||||||
|
public static String convertU8ToHexString(char u8) {
|
||||||
|
return Integer.toHexString(u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split uint8 to 2 bytes of high byte and low byte. e.g. 20 = 0x14 should
|
||||||
|
* be split to [0x01,0x04] 0x01 is high byte and 0x04 is low byte
|
||||||
|
*
|
||||||
|
* @param uint8 the char(uint8)
|
||||||
|
* @return the high and low bytes be split, byte[0] is high and byte[1] is
|
||||||
|
* low
|
||||||
|
*/
|
||||||
|
public static byte[] splitUint8To2bytes(char uint8) {
|
||||||
|
if (uint8 < 0 || uint8 > 0xff) {
|
||||||
|
throw new RuntimeException("Out of Boundary");
|
||||||
|
}
|
||||||
|
String hexString = Integer.toHexString(uint8);
|
||||||
|
byte low;
|
||||||
|
byte high;
|
||||||
|
if (hexString.length() > 1) {
|
||||||
|
high = (byte) Integer.parseInt(hexString.substring(0, 1), 16);
|
||||||
|
low = (byte) Integer.parseInt(hexString.substring(1, 2), 16);
|
||||||
|
} else {
|
||||||
|
high = 0;
|
||||||
|
low = (byte) Integer.parseInt(hexString.substring(0, 1), 16);
|
||||||
|
}
|
||||||
|
byte[] result = new byte[]{high, low};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combine 2 bytes (high byte and low byte) to one whole byte
|
||||||
|
*
|
||||||
|
* @param high the high byte
|
||||||
|
* @param low the low byte
|
||||||
|
* @return the whole byte
|
||||||
|
*/
|
||||||
|
public static byte combine2bytesToOne(byte high, byte low) {
|
||||||
|
if (high < 0 || high > 0xf || low < 0 || low > 0xf) {
|
||||||
|
throw new RuntimeException("Out of Boundary");
|
||||||
|
}
|
||||||
|
return (byte) (high << 4 | low);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combine 2 bytes (high byte and low byte) to
|
||||||
|
*
|
||||||
|
* @param high the high byte
|
||||||
|
* @param low the low byte
|
||||||
|
* @return the char(u8)
|
||||||
|
*/
|
||||||
|
public static char combine2bytesToU16(byte high, byte low) {
|
||||||
|
char highU8 = convertByte2Uint8(high);
|
||||||
|
char lowU8 = convertByte2Uint8(low);
|
||||||
|
return (char) (highU8 << 8 | lowU8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the random byte to be sent
|
||||||
|
*
|
||||||
|
* @return the random byte
|
||||||
|
*/
|
||||||
|
private static byte randomByte() {
|
||||||
|
return (byte) (127 - new Random().nextInt(256));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the random byte to be sent
|
||||||
|
*
|
||||||
|
* @param len the len presented by u8
|
||||||
|
* @return the byte[] to be sent
|
||||||
|
*/
|
||||||
|
public static byte[] randomBytes(char len) {
|
||||||
|
byte[] data = new byte[len];
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
data[i] = randomByte();
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] genSpecBytes(char len) {
|
||||||
|
byte[] data = new byte[len];
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
data[i] = '1';
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the random byte to be sent
|
||||||
|
*
|
||||||
|
* @param len the len presented by byte
|
||||||
|
* @return the byte[] to be sent
|
||||||
|
*/
|
||||||
|
public static byte[] randomBytes(byte len) {
|
||||||
|
char u8 = convertByte2Uint8(len);
|
||||||
|
return randomBytes(u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the specific byte to be sent
|
||||||
|
*
|
||||||
|
* @param len the len presented by byte
|
||||||
|
* @return the byte[]
|
||||||
|
*/
|
||||||
|
public static byte[] genSpecBytes(byte len) {
|
||||||
|
char u8 = convertByte2Uint8(len);
|
||||||
|
return genSpecBytes(u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String parseBssid(byte[] bssidBytes, int offset, int count) {
|
||||||
|
byte[] bytes = new byte[count];
|
||||||
|
System.arraycopy(bssidBytes, offset, bytes, 0, count);
|
||||||
|
return parseBssid(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parse "24,-2,52,-102,-93,-60" to "18,fe,34,9a,a3,c4"
|
||||||
|
* parse the bssid from hex to String
|
||||||
|
*
|
||||||
|
* @param bssidBytes the hex bytes bssid, e.g. {24,-2,52,-102,-93,-60}
|
||||||
|
* @return the String of bssid, e.g. 18fe349aa3c4
|
||||||
|
*/
|
||||||
|
public static String parseBssid(byte[] bssidBytes) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
int k;
|
||||||
|
String hexK;
|
||||||
|
String str;
|
||||||
|
for (byte bssidByte : bssidBytes) {
|
||||||
|
k = 0xff & bssidByte;
|
||||||
|
hexK = Integer.toHexString(k);
|
||||||
|
str = ((k < 16) ? ("0" + hexK) : (hexK));
|
||||||
|
System.out.println(str);
|
||||||
|
sb.append(str);
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string the string to be used
|
||||||
|
* @return the byte[] of String according to {@link #ESPTOUCH_ENCODING_CHARSET}
|
||||||
|
*/
|
||||||
|
public static byte[] getBytesByString(String string) {
|
||||||
|
try {
|
||||||
|
return string.getBytes(ESPTOUCH_ENCODING_CHARSET);
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
throw new IllegalArgumentException("the charset is invalid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void test_splitUint8To2bytes() {
|
||||||
|
// 20 = 0x14
|
||||||
|
byte[] result = splitUint8To2bytes((char) 20);
|
||||||
|
if (result[0] == 1 && result[1] == 4) {
|
||||||
|
System.out.println("test_splitUint8To2bytes(): pass");
|
||||||
|
} else {
|
||||||
|
System.out.println("test_splitUint8To2bytes(): fail");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void test_combine2bytesToOne() {
|
||||||
|
byte high = 0x01;
|
||||||
|
byte low = 0x04;
|
||||||
|
if (combine2bytesToOne(high, low) == 20) {
|
||||||
|
System.out.println("test_combine2bytesToOne(): pass");
|
||||||
|
} else {
|
||||||
|
System.out.println("test_combine2bytesToOne(): fail");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void test_convertChar2Uint8() {
|
||||||
|
byte b1 = 'a';
|
||||||
|
// -128: 1000 0000 should be 128 in unsigned char
|
||||||
|
// -1: 1111 1111 should be 255 in unsigned char
|
||||||
|
byte b2 = (byte) -128;
|
||||||
|
byte b3 = (byte) -1;
|
||||||
|
if (convertByte2Uint8(b1) == 97 && convertByte2Uint8(b2) == 128
|
||||||
|
&& convertByte2Uint8(b3) == 255) {
|
||||||
|
System.out.println("test_convertChar2Uint8(): pass");
|
||||||
|
} else {
|
||||||
|
System.out.println("test_convertChar2Uint8(): fail");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void test_convertUint8toByte() {
|
||||||
|
char c1 = 'a';
|
||||||
|
// 128: 1000 0000 should be -128 in byte
|
||||||
|
// 255: 1111 1111 should be -1 in byte
|
||||||
|
char c2 = 128;
|
||||||
|
char c3 = 255;
|
||||||
|
if (convertUint8toByte(c1) == 97 && convertUint8toByte(c2) == -128
|
||||||
|
&& convertUint8toByte(c3) == -1) {
|
||||||
|
System.out.println("test_convertUint8toByte(): pass");
|
||||||
|
} else {
|
||||||
|
System.out.println("test_convertUint8toByte(): fail");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void test_parseBssid() {
|
||||||
|
byte b[] = {15, -2, 52, -102, -93, -60};
|
||||||
|
if (parseBssid(b).equals("0ffe349aa3c4")) {
|
||||||
|
System.out.println("test_parseBssid(): pass");
|
||||||
|
} else {
|
||||||
|
System.out.println("test_parseBssid(): fail");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String args[]) {
|
||||||
|
test_convertUint8toByte();
|
||||||
|
test_convertChar2Uint8();
|
||||||
|
test_splitUint8To2bytes();
|
||||||
|
test_combine2bytesToOne();
|
||||||
|
test_parseBssid();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
package com.espressif.iot.esptouch.util;
|
||||||
|
|
||||||
|
import java.util.zip.Checksum;
|
||||||
|
|
||||||
|
public class CRC8 implements Checksum {
|
||||||
|
|
||||||
|
private static final short[] crcTable = new short[256];
|
||||||
|
private static final short CRC_POLYNOM = 0x8c;
|
||||||
|
private static final short CRC_INITIAL = 0x00;
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (int dividend = 0; dividend < 256; dividend++) {
|
||||||
|
int remainder = dividend;// << 8;
|
||||||
|
for (int bit = 0; bit < 8; ++bit)
|
||||||
|
if ((remainder & 0x01) != 0)
|
||||||
|
remainder = (remainder >>> 1) ^ CRC_POLYNOM;
|
||||||
|
else
|
||||||
|
remainder >>>= 1;
|
||||||
|
crcTable[dividend] = (short) remainder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final short init;
|
||||||
|
private short value;
|
||||||
|
|
||||||
|
public CRC8() {
|
||||||
|
this.value = this.init = CRC_INITIAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(byte[] buffer, int offset, int len) {
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
int data = buffer[offset + i] ^ value;
|
||||||
|
value = (short) (crcTable[data & 0xff] ^ (value << 8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the current checksum with the specified array of bytes.
|
||||||
|
* Equivalent to calling <code>update(buffer, 0, buffer.length)</code>.
|
||||||
|
*
|
||||||
|
* @param buffer the byte array to update the checksum with
|
||||||
|
*/
|
||||||
|
public void update(byte[] buffer) {
|
||||||
|
update(buffer, 0, buffer.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(int b) {
|
||||||
|
update(new byte[]{(byte) b}, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getValue() {
|
||||||
|
return value & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
value = init;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,104 @@
|
|||||||
|
package com.espressif.iot.esptouch.util;
|
||||||
|
|
||||||
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
import javax.crypto.BadPaddingException;
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.IllegalBlockSizeException;
|
||||||
|
import javax.crypto.NoSuchPaddingException;
|
||||||
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
|
public class EspAES {
|
||||||
|
private static final String TRANSFORMATION_DEFAULT = "AES/ECB/PKCS5Padding";
|
||||||
|
|
||||||
|
private final byte[] mKey;
|
||||||
|
private final byte[] mIV;
|
||||||
|
private final String mTransformation;
|
||||||
|
private Cipher mEncryptCipher;
|
||||||
|
private Cipher mDecryptCipher;
|
||||||
|
|
||||||
|
public EspAES(byte[] key) {
|
||||||
|
this(key, null, TRANSFORMATION_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EspAES(byte[] key, String transformation) {
|
||||||
|
this(key, null, transformation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EspAES(byte[] key, byte[] iv) {
|
||||||
|
this(key, iv, TRANSFORMATION_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EspAES(byte[] key, byte[] iv, String transformation) {
|
||||||
|
mKey = key;
|
||||||
|
mIV = iv;
|
||||||
|
mTransformation = transformation;
|
||||||
|
|
||||||
|
mEncryptCipher = createEncryptCipher();
|
||||||
|
mDecryptCipher = createDecryptCipher();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Cipher createEncryptCipher() {
|
||||||
|
try {
|
||||||
|
Cipher cipher = Cipher.getInstance(mTransformation);
|
||||||
|
|
||||||
|
SecretKeySpec secretKeySpec = new SecretKeySpec(mKey, "AES");
|
||||||
|
if (mIV == null) {
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
|
||||||
|
} else {
|
||||||
|
IvParameterSpec parameterSpec = new IvParameterSpec(mIV);
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, parameterSpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cipher;
|
||||||
|
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException
|
||||||
|
e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Cipher createDecryptCipher() {
|
||||||
|
try {
|
||||||
|
Cipher cipher = Cipher.getInstance(mTransformation);
|
||||||
|
|
||||||
|
SecretKeySpec secretKeySpec = new SecretKeySpec(mKey, "AES");
|
||||||
|
if (mIV == null) {
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
|
||||||
|
} else {
|
||||||
|
IvParameterSpec parameterSpec = new IvParameterSpec(mIV);
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, parameterSpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cipher;
|
||||||
|
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException
|
||||||
|
e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] encrypt(byte[] content) {
|
||||||
|
try {
|
||||||
|
return mEncryptCipher.doFinal(content);
|
||||||
|
} catch (BadPaddingException | IllegalBlockSizeException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] decrypt(byte[] content) {
|
||||||
|
try {
|
||||||
|
return mDecryptCipher.doFinal(content);
|
||||||
|
} catch (BadPaddingException | IllegalBlockSizeException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
package com.espressif.iot.esptouch.util;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.wifi.WifiInfo;
|
||||||
|
import android.net.wifi.WifiManager;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
public class EspNetUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the local ip address by Android System
|
||||||
|
*
|
||||||
|
* @param context the context
|
||||||
|
* @return the local ip addr allocated by Ap
|
||||||
|
*/
|
||||||
|
public static InetAddress getLocalInetAddress(Context context) {
|
||||||
|
WifiManager wm = (WifiManager) context
|
||||||
|
.getSystemService(Context.WIFI_SERVICE);
|
||||||
|
WifiInfo wifiInfo = wm.getConnectionInfo();
|
||||||
|
int localAddrInt = wifiInfo.getIpAddress();
|
||||||
|
String localAddrStr = __formatString(localAddrInt);
|
||||||
|
InetAddress localInetAddr = null;
|
||||||
|
try {
|
||||||
|
localInetAddr = InetAddress.getByName(localAddrStr);
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return localInetAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String __formatString(int value) {
|
||||||
|
String strValue = "";
|
||||||
|
byte[] ary = __intToByteArray(value);
|
||||||
|
for (int i = ary.length - 1; i >= 0; i--) {
|
||||||
|
strValue += (ary[i] & 0xFF);
|
||||||
|
if (i > 0) {
|
||||||
|
strValue += ".";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] __intToByteArray(int value) {
|
||||||
|
byte[] b = new byte[4];
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
int offset = (b.length - 1 - i) * 8;
|
||||||
|
b[i] = (byte) ((value >>> offset) & 0xFF);
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parse InetAddress
|
||||||
|
*
|
||||||
|
* @param inetAddrBytes
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static InetAddress parseInetAddr(byte[] inetAddrBytes, int offset,
|
||||||
|
int count) {
|
||||||
|
InetAddress inetAddress = null;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
sb.append(Integer.toString(inetAddrBytes[offset + i] & 0xff));
|
||||||
|
if (i != count - 1) {
|
||||||
|
sb.append('.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
inetAddress = InetAddress.getByName(sb.toString());
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return inetAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parse bssid
|
||||||
|
*
|
||||||
|
* @param bssid the bssid like aa:bb:cc:dd:ee:ff
|
||||||
|
* @return byte converted from bssid
|
||||||
|
*/
|
||||||
|
public static byte[] parseBssid2bytes(String bssid) {
|
||||||
|
String bssidSplits[] = bssid.split(":");
|
||||||
|
byte[] result = new byte[bssidSplits.length];
|
||||||
|
for (int i = 0; i < bssidSplits.length; i++) {
|
||||||
|
result[i] = (byte) Integer.parseInt(bssidSplits[i], 16);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,237 @@
|
|||||||
|
package de.mc8051.fluttersmartconfig;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.Manifest;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.NetworkInfo;
|
||||||
|
import android.net.wifi.WifiInfo;
|
||||||
|
import android.net.wifi.WifiManager;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.content.ContextWrapper;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.os.Build.VERSION;
|
||||||
|
import android.os.Build.VERSION_CODES;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
|
||||||
|
import com.espressif.iot.esptouch.EsptouchTask;
|
||||||
|
import com.espressif.iot.esptouch.IEsptouchResult;
|
||||||
|
import com.espressif.iot.esptouch.IEsptouchTask;
|
||||||
|
import com.espressif.iot.esptouch.util.ByteUtil;
|
||||||
|
import com.espressif.iot.esptouch.util.EspNetUtil;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import io.flutter.plugin.common.MethodCall;
|
||||||
|
import io.flutter.plugin.common.MethodChannel;
|
||||||
|
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
|
||||||
|
import io.flutter.plugin.common.MethodChannel.Result;
|
||||||
|
import io.flutter.plugin.common.PluginRegistry.Registrar;
|
||||||
|
|
||||||
|
/** FlutterSmartconfigPlugin */
|
||||||
|
public class FlutterSmartconfigPlugin implements MethodCallHandler {
|
||||||
|
private IEsptouchTask mEsptouchTask;
|
||||||
|
|
||||||
|
private Context moContext;
|
||||||
|
private Activity moActivity;
|
||||||
|
|
||||||
|
private FlutterSmartconfigPlugin(Activity poActivity) {
|
||||||
|
this.moActivity = poActivity;
|
||||||
|
this.moContext = poActivity.getApplicationContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void registerWith(Registrar registrar) {
|
||||||
|
final MethodChannel channel = new MethodChannel(registrar.messenger(), "plugins.flutter.io/flutter_smartconfig");
|
||||||
|
channel.setMethodCallHandler(new FlutterSmartconfigPlugin(registrar.activity()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMethodCall(MethodCall call, Result result) {
|
||||||
|
if (call.method.equals("startSmartConfig")) {
|
||||||
|
String ssid = call.argument("ssid");
|
||||||
|
String bssid = call.argument("bssid");
|
||||||
|
String pass = call.argument("pass");
|
||||||
|
String deviceCount = call.argument("deviceCount");
|
||||||
|
String broadcast = call.argument("broadcast");
|
||||||
|
|
||||||
|
startSmartConfig(ssid, bssid, pass, deviceCount, broadcast, result);
|
||||||
|
} else if (call.method.equals("stopSmartConfig")) {
|
||||||
|
stopSmartConfig();
|
||||||
|
} else if (call.method.equals("getConnectedWiFiInfo")) {
|
||||||
|
getWifiInfo(result);
|
||||||
|
} else {
|
||||||
|
result.notImplemented();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getWifiInfo(Result result) {
|
||||||
|
final ConnectivityManager connManager = (ConnectivityManager) moContext.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
|
final NetworkInfo activeNetwork = connManager.getActiveNetworkInfo();
|
||||||
|
|
||||||
|
if (activeNetwork != null && activeNetwork.getType() == ConnectivityManager.TYPE_WIFI) {
|
||||||
|
final WifiManager wifiManager = (WifiManager) moContext.getSystemService(Context.WIFI_SERVICE);
|
||||||
|
final WifiInfo wifiInfo = wifiManager.getConnectionInfo();
|
||||||
|
|
||||||
|
if (wifiInfo != null) {
|
||||||
|
final String ssid = wifiInfo.getSSID().replaceAll("^\"|\"$", "");
|
||||||
|
final String bssid = wifiInfo.getBSSID();
|
||||||
|
String is5G = "unknow";
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
int frequency = wifiInfo.getFrequency();
|
||||||
|
if (frequency > 4900 && frequency < 5900) {
|
||||||
|
// Connected 5G wifi. Device does not support 5G
|
||||||
|
is5G = "yes";
|
||||||
|
} else {
|
||||||
|
is5G = "no";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject re = new JSONObject();
|
||||||
|
try {
|
||||||
|
re.put("ssid", ssid);
|
||||||
|
re.put("bssid", bssid);
|
||||||
|
re.put("is5G", is5G);
|
||||||
|
} catch (JSONException ex) {
|
||||||
|
result.error("getWifiInfo", ex.getMessage(), null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.success(re.toString());
|
||||||
|
} else {
|
||||||
|
result.error("getWifiInfo", "Unable to obtain WiFi details", null);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.error("getWifiInfo", "Not connected to WiFi", null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void stopSmartConfig() {
|
||||||
|
if (mEsptouchTask != null) {
|
||||||
|
mEsptouchTask.interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startSmartConfig(String ssid, String bssid, String pass, String deviceCount, String broadcast, final Result resultResp) {
|
||||||
|
stopSmartConfig();
|
||||||
|
byte[] apSsid = ByteUtil.getBytesByString(ssid);
|
||||||
|
byte[] apBssid = EspNetUtil.parseBssid2bytes(bssid);
|
||||||
|
byte[] apPassword = ByteUtil.getBytesByString(pass);
|
||||||
|
byte[] deviceCountData = deviceCount.getBytes();
|
||||||
|
byte[] broadcastData = broadcast.getBytes();
|
||||||
|
|
||||||
|
new EsptouchAsyncTask4(new TaskListener() {
|
||||||
|
@Override
|
||||||
|
public void onFinished(List < IEsptouchResult > result) {
|
||||||
|
// Do Something after the task has finished
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
IEsptouchResult firstResult = result.get(0);
|
||||||
|
|
||||||
|
if (!firstResult.isCancelled()) {
|
||||||
|
if (firstResult.isSuc()) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
JSONArray jsonArray = new JSONArray();
|
||||||
|
|
||||||
|
for (IEsptouchResult resultInList: result) {
|
||||||
|
if (!resultInList.isCancelled() && resultInList.getBssid() != null) {
|
||||||
|
|
||||||
|
sb.append("Esptouch success, bssid = ")
|
||||||
|
.append(resultInList.getBssid())
|
||||||
|
.append(", InetAddress = ")
|
||||||
|
.append(resultInList.getInetAddress().getHostAddress())
|
||||||
|
.append("\n");
|
||||||
|
|
||||||
|
JSONObject re = new JSONObject();
|
||||||
|
re.put("bssid", resultInList.getBssid());
|
||||||
|
re.put("ip", resultInList.getInetAddress().getHostAddress());
|
||||||
|
jsonArray.put(re);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject configureDeviceObj = new JSONObject();
|
||||||
|
configureDeviceObj.put("devices", jsonArray);
|
||||||
|
resultResp.success(configureDeviceObj.toString());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
resultResp.error("startSmartConfig", "Esptouch fail", null);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resultResp.error("startSmartConfig", "Esptouch cancelled", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception err) {
|
||||||
|
resultResp.error("startSmartConfig", err.getMessage(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}).execute(apSsid, apBssid, apPassword, deviceCountData, broadcastData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface TaskListener {
|
||||||
|
public void onFinished(List < IEsptouchResult > result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class EsptouchAsyncTask4 extends AsyncTask < byte[], Void, List < IEsptouchResult >> {
|
||||||
|
private final TaskListener taskListener;
|
||||||
|
|
||||||
|
public EsptouchAsyncTask4(TaskListener listener) {
|
||||||
|
// The listener reference is passed in through the constructor
|
||||||
|
this.taskListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Object mLock = new Object();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPreExecute() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List < IEsptouchResult > doInBackground(byte[]...params) {
|
||||||
|
int taskResultCount;
|
||||||
|
|
||||||
|
synchronized(mLock) {
|
||||||
|
byte[] apSsid = params[0];
|
||||||
|
byte[] apBssid = params[1];
|
||||||
|
byte[] apPassword = params[2];
|
||||||
|
byte[] deviceCountData = params[3];
|
||||||
|
byte[] broadcastData = params[4];
|
||||||
|
|
||||||
|
taskResultCount = deviceCountData.length == 0 ? -1 : Integer.parseInt(new String(deviceCountData));
|
||||||
|
|
||||||
|
mEsptouchTask = new EsptouchTask(apSsid, apBssid, apPassword, moContext);
|
||||||
|
mEsptouchTask.setPackageBroadcast(broadcastData[0] == 1); // true is broadcast, false is multicast
|
||||||
|
}
|
||||||
|
|
||||||
|
List < IEsptouchResult > resultList = mEsptouchTask.executeForResults(taskResultCount);
|
||||||
|
return resultList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(List < IEsptouchResult > result) {
|
||||||
|
|
||||||
|
IEsptouchResult firstResult = result.get(0);
|
||||||
|
// check whether the task is cancelled and no results received
|
||||||
|
if (!firstResult.isCancelled()) {
|
||||||
|
if (this.taskListener != null) {
|
||||||
|
// And if it is we call the callback function on it.
|
||||||
|
this.taskListener.onFinished(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
71
example/.gitignore
vendored
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
# Miscellaneous
|
||||||
|
*.class
|
||||||
|
*.lock
|
||||||
|
*.log
|
||||||
|
*.pyc
|
||||||
|
*.swp
|
||||||
|
.DS_Store
|
||||||
|
.atom/
|
||||||
|
.buildlog/
|
||||||
|
.history
|
||||||
|
.svn/
|
||||||
|
|
||||||
|
# IntelliJ related
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# Visual Studio Code related
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
# Flutter/Dart/Pub related
|
||||||
|
**/doc/api/
|
||||||
|
.dart_tool/
|
||||||
|
.flutter-plugins
|
||||||
|
.packages
|
||||||
|
.pub-cache/
|
||||||
|
.pub/
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Android related
|
||||||
|
**/android/**/gradle-wrapper.jar
|
||||||
|
**/android/.gradle
|
||||||
|
**/android/captures/
|
||||||
|
**/android/gradlew
|
||||||
|
**/android/gradlew.bat
|
||||||
|
**/android/local.properties
|
||||||
|
**/android/**/GeneratedPluginRegistrant.java
|
||||||
|
|
||||||
|
# iOS/XCode related
|
||||||
|
**/ios/**/*.mode1v3
|
||||||
|
**/ios/**/*.mode2v3
|
||||||
|
**/ios/**/*.moved-aside
|
||||||
|
**/ios/**/*.pbxuser
|
||||||
|
**/ios/**/*.perspectivev3
|
||||||
|
**/ios/**/*sync/
|
||||||
|
**/ios/**/.sconsign.dblite
|
||||||
|
**/ios/**/.tags*
|
||||||
|
**/ios/**/.vagrant/
|
||||||
|
**/ios/**/DerivedData/
|
||||||
|
**/ios/**/Icon?
|
||||||
|
**/ios/**/Pods/
|
||||||
|
**/ios/**/.symlinks/
|
||||||
|
**/ios/**/profile
|
||||||
|
**/ios/**/xcuserdata
|
||||||
|
**/ios/.generated/
|
||||||
|
**/ios/Flutter/App.framework
|
||||||
|
**/ios/Flutter/Flutter.framework
|
||||||
|
**/ios/Flutter/Generated.xcconfig
|
||||||
|
**/ios/Flutter/app.flx
|
||||||
|
**/ios/Flutter/app.zip
|
||||||
|
**/ios/Flutter/flutter_assets/
|
||||||
|
**/ios/ServiceDefinitions.json
|
||||||
|
**/ios/Runner/GeneratedPluginRegistrant.*
|
||||||
|
|
||||||
|
# Exceptions to above rules.
|
||||||
|
!**/ios/**/default.mode1v3
|
||||||
|
!**/ios/**/default.mode2v3
|
||||||
|
!**/ios/**/default.pbxuser
|
||||||
|
!**/ios/**/default.perspectivev3
|
||||||
|
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
|
10
example/.metadata
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# 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: 5391447fae6209bb21a89e6a5a6583cac1af9b4b
|
||||||
|
channel: beta
|
||||||
|
|
||||||
|
project_type: app
|
16
example/README.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# flutter_smartconfig_example
|
||||||
|
|
||||||
|
Demonstrates how to use the flutter_smartconfig plugin.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
This project is a starting point for a Flutter application.
|
||||||
|
|
||||||
|
A few resources to get you started if this is your first Flutter project:
|
||||||
|
|
||||||
|
- [Lab: Write your first Flutter app](https://flutter.io/docs/get-started/codelab)
|
||||||
|
- [Cookbook: Useful Flutter samples](https://flutter.io/docs/cookbook)
|
||||||
|
|
||||||
|
For help getting started with Flutter, view our
|
||||||
|
[online documentation](https://flutter.io/docs), which offers tutorials,
|
||||||
|
samples, guidance on mobile development, and a full API reference.
|
61
example/android/app/build.gradle
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
def localProperties = new Properties()
|
||||||
|
def localPropertiesFile = rootProject.file('local.properties')
|
||||||
|
if (localPropertiesFile.exists()) {
|
||||||
|
localPropertiesFile.withReader('UTF-8') { reader ->
|
||||||
|
localProperties.load(reader)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def flutterRoot = localProperties.getProperty('flutter.sdk')
|
||||||
|
if (flutterRoot == null) {
|
||||||
|
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
|
||||||
|
}
|
||||||
|
|
||||||
|
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
|
||||||
|
if (flutterVersionCode == null) {
|
||||||
|
flutterVersionCode = '1'
|
||||||
|
}
|
||||||
|
|
||||||
|
def flutterVersionName = localProperties.getProperty('flutter.versionName')
|
||||||
|
if (flutterVersionName == null) {
|
||||||
|
flutterVersionName = '1.0'
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'com.android.application'
|
||||||
|
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 27
|
||||||
|
|
||||||
|
lintOptions {
|
||||||
|
disable 'InvalidPackage'
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||||
|
applicationId "de.mc8051.fluttersmartconfigexample"
|
||||||
|
minSdkVersion 16
|
||||||
|
targetSdkVersion 27
|
||||||
|
versionCode flutterVersionCode.toInteger()
|
||||||
|
versionName flutterVersionName
|
||||||
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
// TODO: Add your own signing config for the release build.
|
||||||
|
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||||
|
signingConfig signingConfigs.debug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flutter {
|
||||||
|
source '../..'
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
testImplementation 'junit:junit:4.12'
|
||||||
|
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||||
|
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||||
|
}
|
39
example/android/app/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="de.mc8051.fluttersmartconfigexample">
|
||||||
|
|
||||||
|
<!-- The INTERNET permission is required for development. Specifically,
|
||||||
|
flutter needs it to communicate with the running application
|
||||||
|
to allow setting breakpoints, to provide hot reload, etc.
|
||||||
|
-->
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
|
||||||
|
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
|
||||||
|
calls FlutterMain.startInitialization(this); in its onCreate method.
|
||||||
|
In most cases you can leave this as-is, but you if you want to provide
|
||||||
|
additional functionality it is fine to subclass or reimplement
|
||||||
|
FlutterApplication and put your custom class here. -->
|
||||||
|
<application
|
||||||
|
android:name="io.flutter.app.FlutterApplication"
|
||||||
|
android:label="flutter_smartconfig_example"
|
||||||
|
android:icon="@mipmap/ic_launcher">
|
||||||
|
<activity
|
||||||
|
android:name=".MainActivity"
|
||||||
|
android:launchMode="singleTop"
|
||||||
|
android:theme="@style/LaunchTheme"
|
||||||
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
|
||||||
|
android:hardwareAccelerated="true"
|
||||||
|
android:windowSoftInputMode="adjustResize">
|
||||||
|
<!-- This keeps the window background of the activity showing
|
||||||
|
until Flutter renders its first frame. It can be removed if
|
||||||
|
there is no splash screen (such as the default splash screen
|
||||||
|
defined in @style/LaunchTheme). -->
|
||||||
|
<meta-data
|
||||||
|
android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
|
||||||
|
android:value="true" />
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
</application>
|
||||||
|
</manifest>
|
@ -0,0 +1,13 @@
|
|||||||
|
package de.mc8051.fluttersmartconfigexample;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import io.flutter.app.FlutterActivity;
|
||||||
|
import io.flutter.plugins.GeneratedPluginRegistrant;
|
||||||
|
|
||||||
|
public class MainActivity extends FlutterActivity {
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
GeneratedPluginRegistrant.registerWith(this);
|
||||||
|
}
|
||||||
|
}
|
@ -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>
|
BIN
example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 544 B |
BIN
example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 442 B |
BIN
example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 721 B |
BIN
example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
8
example/android/app/src/main/res/values/styles.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
|
<!-- Show a splash screen on the activity. Automatically removed when
|
||||||
|
Flutter draws its first frame -->
|
||||||
|
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
29
example/android/build.gradle
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.android.tools.build:gradle:3.2.1'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.buildDir = '../build'
|
||||||
|
subprojects {
|
||||||
|
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
||||||
|
}
|
||||||
|
subprojects {
|
||||||
|
project.evaluationDependsOn(':app')
|
||||||
|
}
|
||||||
|
|
||||||
|
task clean(type: Delete) {
|
||||||
|
delete rootProject.buildDir
|
||||||
|
}
|
1
example/android/gradle.properties
Normal file
@ -0,0 +1 @@
|
|||||||
|
org.gradle.jvmargs=-Xmx1536M
|
6
example/android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#Fri Jun 23 08:50:38 CEST 2017
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
|
15
example/android/settings.gradle
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
include ':app'
|
||||||
|
|
||||||
|
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
|
||||||
|
|
||||||
|
def plugins = new Properties()
|
||||||
|
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
|
||||||
|
if (pluginsFile.exists()) {
|
||||||
|
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins.each { name, path ->
|
||||||
|
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
|
||||||
|
include ":$name"
|
||||||
|
project(":$name").projectDir = pluginDirectory
|
||||||
|
}
|
26
example/ios/Flutter/AppFrameworkInfo.plist
Normal file
@ -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>8.0</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
1
example/ios/Flutter/Debug.xcconfig
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include "Generated.xcconfig"
|
1
example/ios/Flutter/Release.xcconfig
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include "Generated.xcconfig"
|
510
example/ios/Runner.xcodeproj/project.pbxproj
Normal file
@ -0,0 +1,510 @@
|
|||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 46;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||||
|
2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; };
|
||||||
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||||
|
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
|
||||||
|
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||||
|
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
|
||||||
|
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||||
|
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
|
||||||
|
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
|
||||||
|
97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
|
||||||
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||||
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||||
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
|
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
||||||
|
isa = PBXCopyFilesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
dstPath = "";
|
||||||
|
dstSubfolderSpec = 10;
|
||||||
|
files = (
|
||||||
|
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
|
||||||
|
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
|
||||||
|
);
|
||||||
|
name = "Embed Frameworks";
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||||
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||||
|
2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; };
|
||||||
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||||
|
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
|
||||||
|
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||||
|
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||||
|
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||||
|
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||||
|
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||||
|
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
|
||||||
|
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||||
|
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||||
|
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
|
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
|
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
|
||||||
|
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
2D5378251FAA1A9400D5DBA9 /* flutter_assets */,
|
||||||
|
3B80C3931E831B6300D905FE /* App.framework */,
|
||||||
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
|
||||||
|
9740EEBA1CF902C7004384FC /* Flutter.framework */,
|
||||||
|
9740EEB21CF90195004384FC /* Debug.xcconfig */,
|
||||||
|
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
|
||||||
|
9740EEB31CF90195004384FC /* Generated.xcconfig */,
|
||||||
|
);
|
||||||
|
name = Flutter;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
97C146E51CF9000F007C117D = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
9740EEB11CF90186004384FC /* Flutter */,
|
||||||
|
97C146F01CF9000F007C117D /* Runner */,
|
||||||
|
97C146EF1CF9000F007C117D /* Products */,
|
||||||
|
CF3B75C9A7D2FA2A4C99F110 /* Frameworks */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
97C146EF1CF9000F007C117D /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
97C146EE1CF9000F007C117D /* Runner.app */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
97C146F01CF9000F007C117D /* Runner */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
|
||||||
|
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
|
||||||
|
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
||||||
|
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||||
|
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||||
|
97C147021CF9000F007C117D /* Info.plist */,
|
||||||
|
97C146F11CF9000F007C117D /* Supporting Files */,
|
||||||
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
||||||
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
||||||
|
);
|
||||||
|
path = Runner;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
97C146F11CF9000F007C117D /* Supporting Files */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
97C146F21CF9000F007C117D /* main.m */,
|
||||||
|
);
|
||||||
|
name = "Supporting Files";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
97C146ED1CF9000F007C117D /* Runner */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||||
|
buildPhases = (
|
||||||
|
9740EEB61CF901F6004384FC /* Run Script */,
|
||||||
|
97C146EA1CF9000F007C117D /* Sources */,
|
||||||
|
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||||
|
97C146EC1CF9000F007C117D /* Resources */,
|
||||||
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = Runner;
|
||||||
|
productName = Runner;
|
||||||
|
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
|
||||||
|
productType = "com.apple.product-type.application";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
97C146E61CF9000F007C117D /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
LastUpgradeCheck = 0910;
|
||||||
|
ORGANIZATIONNAME = "The Chromium Authors";
|
||||||
|
TargetAttributes = {
|
||||||
|
97C146ED1CF9000F007C117D = {
|
||||||
|
CreatedOnToolsVersion = 7.3.1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
||||||
|
compatibilityVersion = "Xcode 3.2";
|
||||||
|
developmentRegion = English;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
Base,
|
||||||
|
);
|
||||||
|
mainGroup = 97C146E51CF9000F007C117D;
|
||||||
|
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
97C146ED1CF9000F007C117D /* Runner */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
97C146EC1CF9000F007C117D /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
|
||||||
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
||||||
|
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
|
||||||
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
||||||
|
2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */,
|
||||||
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
name = "Thin Binary";
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
|
||||||
|
};
|
||||||
|
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
name = "Run Script";
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||||
|
};
|
||||||
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
97C146EA1CF9000F007C117D /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
|
||||||
|
97C146F31CF9000F007C117D /* main.m in Sources */,
|
||||||
|
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXVariantGroup section */
|
||||||
|
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
97C146FB1CF9000F007C117D /* Base */,
|
||||||
|
);
|
||||||
|
name = Main.storyboard;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
97C147001CF9000F007C117D /* Base */,
|
||||||
|
);
|
||||||
|
name = LaunchScreen.storyboard;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXVariantGroup section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
249021D3217E4FDB00AE95B9 /* Profile */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
};
|
||||||
|
name = Profile;
|
||||||
|
};
|
||||||
|
249021D4217E4FDB00AE95B9 /* Profile */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
|
DEVELOPMENT_TEAM = S8QB4VV633;
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(PROJECT_DIR)/Flutter",
|
||||||
|
);
|
||||||
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(PROJECT_DIR)/Flutter",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = de.mc8051.flutterSmartconfigExample;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
};
|
||||||
|
name = Profile;
|
||||||
|
};
|
||||||
|
97C147031CF9000F007C117D /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
97C147041CF9000F007C117D /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
97C147061CF9000F007C117D /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(PROJECT_DIR)/Flutter",
|
||||||
|
);
|
||||||
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(PROJECT_DIR)/Flutter",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = de.mc8051.flutterSmartconfigExample;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
97C147071CF9000F007C117D /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(PROJECT_DIR)/Flutter",
|
||||||
|
);
|
||||||
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(PROJECT_DIR)/Flutter",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = de.mc8051.flutterSmartconfigExample;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
97C147031CF9000F007C117D /* Debug */,
|
||||||
|
97C147041CF9000F007C117D /* Release */,
|
||||||
|
249021D3217E4FDB00AE95B9 /* Profile */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
97C147061CF9000F007C117D /* Debug */,
|
||||||
|
97C147071CF9000F007C117D /* Release */,
|
||||||
|
249021D4217E4FDB00AE95B9 /* Profile */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
||||||
|
}
|
7
example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "group:Runner.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
@ -0,0 +1,93 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "0910"
|
||||||
|
version = "1.3">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
language = ""
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
|
<Testables>
|
||||||
|
</Testables>
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
language = ""
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Profile"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
7
example/ios/Runner.xcworkspace/contents.xcworkspacedata
generated
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "group:Runner.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
6
example/ios/Runner/AppDelegate.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#import <Flutter/Flutter.h>
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
@interface AppDelegate : FlutterAppDelegate
|
||||||
|
|
||||||
|
@end
|
13
example/ios/Runner/AppDelegate.m
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#include "AppDelegate.h"
|
||||||
|
#include "GeneratedPluginRegistrant.h"
|
||||||
|
|
||||||
|
@implementation AppDelegate
|
||||||
|
|
||||||
|
- (BOOL)application:(UIApplication *)application
|
||||||
|
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
||||||
|
[GeneratedPluginRegistrant registerWithRegistry:self];
|
||||||
|
// Override point for customization after application launch.
|
||||||
|
return [super application:application didFinishLaunchingWithOptions:launchOptions];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
@ -0,0 +1,122 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-20x20@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-20x20@3x.png",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-29x29@1x.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-29x29@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-29x29@3x.png",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-40x40@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-40x40@3x.png",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "60x60",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-60x60@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "60x60",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-60x60@3x.png",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-20x20@1x.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-20x20@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-29x29@1x.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-29x29@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-40x40@1x.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-40x40@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "76x76",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-76x76@1x.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "76x76",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-76x76@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "83.5x83.5",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-83.5x83.5@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "1024x1024",
|
||||||
|
"idiom" : "ios-marketing",
|
||||||
|
"filename" : "Icon-App-1024x1024@1x.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 564 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 3.5 KiB |
23
example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "LaunchImage.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "LaunchImage@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "LaunchImage@3x.png",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
BIN
example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
vendored
Normal file
After Width: | Height: | Size: 68 B |
BIN
example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
vendored
Normal file
After Width: | Height: | Size: 68 B |
BIN
example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
vendored
Normal file
After Width: | Height: | Size: 68 B |
5
example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Launch Screen Assets
|
||||||
|
|
||||||
|
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
|
||||||
|
|
||||||
|
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
|
37
example/ios/Runner/Base.lproj/LaunchScreen.storyboard
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="iOS"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--View Controller-->
|
||||||
|
<scene sceneID="EHf-IW-A2E">
|
||||||
|
<objects>
|
||||||
|
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||||
|
<layoutGuides>
|
||||||
|
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
|
||||||
|
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
|
||||||
|
</layoutGuides>
|
||||||
|
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
|
||||||
|
</imageView>
|
||||||
|
</subviews>
|
||||||
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
|
||||||
|
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
|
||||||
|
</constraints>
|
||||||
|
</view>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="53" y="375"/>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
<resources>
|
||||||
|
<image name="LaunchImage" width="168" height="185"/>
|
||||||
|
</resources>
|
||||||
|
</document>
|
26
example/ios/Runner/Base.lproj/Main.storyboard
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="iOS"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--Flutter View Controller-->
|
||||||
|
<scene sceneID="tne-QT-ifu">
|
||||||
|
<objects>
|
||||||
|
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
|
||||||
|
<layoutGuides>
|
||||||
|
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
|
||||||
|
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||||
|
</layoutGuides>
|
||||||
|
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||||
|
</view>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
</document>
|
45
example/ios/Runner/Info.plist
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?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>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>flutter_smartconfig_example</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||||
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
<true/>
|
||||||
|
<key>UILaunchStoryboardName</key>
|
||||||
|
<string>LaunchScreen</string>
|
||||||
|
<key>UIMainStoryboardFile</key>
|
||||||
|
<string>Main</string>
|
||||||
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
9
example/ios/Runner/main.m
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#import <Flutter/Flutter.h>
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#import "AppDelegate.h"
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
@autoreleasepool {
|
||||||
|
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
|
||||||
|
}
|
||||||
|
}
|
187
example/lib/main.dart
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:flutter_smartconfig/flutter_smartconfig.dart';
|
||||||
|
|
||||||
|
void main() => runApp(MyApp());
|
||||||
|
|
||||||
|
class MyApp extends StatelessWidget {
|
||||||
|
// This widget is the root of your application.
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MaterialApp(
|
||||||
|
title: 'ESP Onetouch Demo',
|
||||||
|
theme: ThemeData(
|
||||||
|
primarySwatch: Colors.blue,
|
||||||
|
),
|
||||||
|
home: MyHomePage(title: 'ESP Onetouch Demo'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyHomePage extends StatefulWidget {
|
||||||
|
MyHomePage({Key key, this.title}) : super(key: key);
|
||||||
|
|
||||||
|
final String title;
|
||||||
|
|
||||||
|
@override
|
||||||
|
_MyHomePageState createState() => _MyHomePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MyHomePageState extends State<MyHomePage> {
|
||||||
|
final TextEditingController _bssidFilter = new TextEditingController();
|
||||||
|
final TextEditingController _ssidFilter = new TextEditingController();
|
||||||
|
final TextEditingController _passwordFilter = new TextEditingController();
|
||||||
|
|
||||||
|
bool _isLoading = false;
|
||||||
|
|
||||||
|
String _ssid = "";
|
||||||
|
String _bssid = "";
|
||||||
|
String _password = "";
|
||||||
|
|
||||||
|
_MyHomePageState() {
|
||||||
|
_ssidFilter.addListener(_ssidListen);
|
||||||
|
_passwordFilter.addListener(_passwordListen);
|
||||||
|
_bssidFilter.addListener(_bssidListen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _ssidListen() {
|
||||||
|
if (_ssidFilter.text.isEmpty) {
|
||||||
|
_ssid = "";
|
||||||
|
} else {
|
||||||
|
_ssid = _ssidFilter.text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _bssidListen() {
|
||||||
|
if (_bssidFilter.text.isEmpty) {
|
||||||
|
_bssid = "";
|
||||||
|
} else {
|
||||||
|
_bssid = _bssidFilter.text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _passwordListen() {
|
||||||
|
if (_passwordFilter.text.isEmpty) {
|
||||||
|
_password = "";
|
||||||
|
} else {
|
||||||
|
_password = _passwordFilter.text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _configureEsp() async {
|
||||||
|
setState(() {
|
||||||
|
_isLoading = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
dynamic data = await FlutterSmartconfig.configureEsp(
|
||||||
|
ssid: _ssid, bssid: _bssid, password: _password);
|
||||||
|
|
||||||
|
print(data);
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_isLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _getConnectedWiFiInfo() async {
|
||||||
|
Map<PermissionGroup, PermissionStatus> permissions =
|
||||||
|
await PermissionHandler().requestPermissions([
|
||||||
|
PermissionGroup.location,
|
||||||
|
PermissionGroup.locationAlways,
|
||||||
|
PermissionGroup.locationWhenInUse
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (permissions[PermissionGroup.location] != PermissionStatus.granted ||
|
||||||
|
permissions[PermissionGroup.locationAlways] !=
|
||||||
|
PermissionStatus.granted ||
|
||||||
|
permissions[PermissionGroup.locationWhenInUse] !=
|
||||||
|
PermissionStatus.granted) {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: new Text("Fehler!"),
|
||||||
|
content: new Text(
|
||||||
|
"Wir benötigen Zugriff auf deinen Standort um auf die WLAN Funktion deines Betriessystems zugreifen zu können!"),
|
||||||
|
actions: <Widget>[
|
||||||
|
new FlatButton(
|
||||||
|
child: new Text("Close"),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, String> data = await FlutterSmartconfig.getConnectedWiFiInfo();
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_ssidFilter.text = data["ssid"];
|
||||||
|
_bssidFilter.text = data["bssid"];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(widget.title),
|
||||||
|
),
|
||||||
|
body: Center(
|
||||||
|
child: _isLoading
|
||||||
|
? Container(
|
||||||
|
child: Center(
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
valueColor:
|
||||||
|
AlwaysStoppedAnimation<Color>(Colors.lightBlue),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
color: Colors.white.withOpacity(0.8),
|
||||||
|
)
|
||||||
|
: new Container(
|
||||||
|
padding: new EdgeInsets.all(10.0),
|
||||||
|
child: new Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
new Container(height: 10),
|
||||||
|
new Container(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: <Widget>[
|
||||||
|
Text("ESP Touch v0.3.7.0"),
|
||||||
|
new TextField(
|
||||||
|
controller: _ssidFilter,
|
||||||
|
decoration:
|
||||||
|
new InputDecoration(labelText: 'ssid'),
|
||||||
|
),
|
||||||
|
new TextField(
|
||||||
|
controller: _bssidFilter,
|
||||||
|
decoration:
|
||||||
|
new InputDecoration(labelText: 'bssid'),
|
||||||
|
),
|
||||||
|
RaisedButton(
|
||||||
|
child: Text('Get Connected WiFi details'),
|
||||||
|
onPressed: _getConnectedWiFiInfo,
|
||||||
|
)
|
||||||
|
])),
|
||||||
|
new Container(
|
||||||
|
child: new TextField(
|
||||||
|
controller: _passwordFilter,
|
||||||
|
decoration:
|
||||||
|
new InputDecoration(labelText: 'Password'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
new RaisedButton(
|
||||||
|
child: new Text('Configure ESP'),
|
||||||
|
onPressed: _configureEsp,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
))) // This trailing comma makes auto-formatting nicer for build methods.
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
64
example/pubspec.yaml
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
name: flutter_smartconfig_example
|
||||||
|
description: Demonstrates how to use the flutter_smartconfig plugin.
|
||||||
|
publish_to: 'none'
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: ">=2.0.0-dev.68.0 <3.0.0"
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
flutter:
|
||||||
|
sdk: flutter
|
||||||
|
|
||||||
|
# The following adds the Cupertino Icons font to your application.
|
||||||
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
|
cupertino_icons: ^0.1.2
|
||||||
|
permission_handler: ^2.1.2
|
||||||
|
|
||||||
|
dev_dependencies:
|
||||||
|
flutter_test:
|
||||||
|
sdk: flutter
|
||||||
|
|
||||||
|
flutter_smartconfig:
|
||||||
|
path: ../
|
||||||
|
|
||||||
|
# For information on the generic Dart part of this file, see the
|
||||||
|
# following page: https://www.dartlang.org/tools/pub/pubspec
|
||||||
|
|
||||||
|
# The following section is specific to Flutter.
|
||||||
|
flutter:
|
||||||
|
|
||||||
|
# The following line ensures that the Material Icons font is
|
||||||
|
# included with your application, so that you can use the icons in
|
||||||
|
# the material Icons class.
|
||||||
|
uses-material-design: true
|
||||||
|
|
||||||
|
# To add assets to your application, add an assets section, like this:
|
||||||
|
# assets:
|
||||||
|
# - images/a_dot_burr.jpeg
|
||||||
|
# - images/a_dot_ham.jpeg
|
||||||
|
|
||||||
|
# An image asset can refer to one or more resolution-specific "variants", see
|
||||||
|
# https://flutter.io/assets-and-images/#resolution-aware.
|
||||||
|
|
||||||
|
# For details regarding adding assets from package dependencies, see
|
||||||
|
# https://flutter.io/assets-and-images/#from-packages
|
||||||
|
|
||||||
|
# To add custom fonts to your application, add a fonts section here,
|
||||||
|
# in this "flutter" section. Each entry in this list should have a
|
||||||
|
# "family" key with the font family name, and a "fonts" key with a
|
||||||
|
# list giving the asset and other descriptors for the font. For
|
||||||
|
# example:
|
||||||
|
# fonts:
|
||||||
|
# - family: Schyler
|
||||||
|
# fonts:
|
||||||
|
# - asset: fonts/Schyler-Regular.ttf
|
||||||
|
# - asset: fonts/Schyler-Italic.ttf
|
||||||
|
# style: italic
|
||||||
|
# - family: Trajan Pro
|
||||||
|
# fonts:
|
||||||
|
# - asset: fonts/TrajanPro.ttf
|
||||||
|
# - asset: fonts/TrajanPro_Bold.ttf
|
||||||
|
# weight: 700
|
||||||
|
#
|
||||||
|
# For details regarding fonts from package dependencies,
|
||||||
|
# see https://flutter.io/custom-fonts/#from-packages
|
27
example/test/widget_test.dart
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// This is a basic Flutter widget test.
|
||||||
|
//
|
||||||
|
// To perform an interaction with a widget in your test, use the WidgetTester
|
||||||
|
// utility that Flutter provides. For example, you can send tap and scroll
|
||||||
|
// gestures. You can also use WidgetTester to find child widgets in the widget
|
||||||
|
// tree, read text, and verify that the values of widget properties are correct.
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
import 'package:flutter_smartconfig_example/main.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets('Verify Platform version', (WidgetTester tester) async {
|
||||||
|
// Build our app and trigger a frame.
|
||||||
|
await tester.pumpWidget(MyApp());
|
||||||
|
|
||||||
|
// Verify that platform version is retrieved.
|
||||||
|
expect(
|
||||||
|
find.byWidgetPredicate(
|
||||||
|
(Widget widget) => widget is Text &&
|
||||||
|
widget.data.startsWith('Running on:'),
|
||||||
|
),
|
||||||
|
findsOneWidget,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
19
flutter_smartconfig.iml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/lib" isTestSource="false" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.idea" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.pub" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/example/.pub" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/example/build" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="library" name="Dart Packages" level="project" />
|
||||||
|
<orderEntry type="library" name="Dart SDK" level="project" />
|
||||||
|
<orderEntry type="library" name="Flutter Plugins" level="project" />
|
||||||
|
</component>
|
||||||
|
</module>
|
36
ios/.gitignore
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
.idea/
|
||||||
|
.vagrant/
|
||||||
|
.sconsign.dblite
|
||||||
|
.svn/
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
*.swp
|
||||||
|
profile
|
||||||
|
|
||||||
|
DerivedData/
|
||||||
|
build/
|
||||||
|
GeneratedPluginRegistrant.h
|
||||||
|
GeneratedPluginRegistrant.m
|
||||||
|
|
||||||
|
.generated/
|
||||||
|
|
||||||
|
*.pbxuser
|
||||||
|
*.mode1v3
|
||||||
|
*.mode2v3
|
||||||
|
*.perspectivev3
|
||||||
|
|
||||||
|
!default.pbxuser
|
||||||
|
!default.mode1v3
|
||||||
|
!default.mode2v3
|
||||||
|
!default.perspectivev3
|
||||||
|
|
||||||
|
xcuserdata
|
||||||
|
|
||||||
|
*.moved-aside
|
||||||
|
|
||||||
|
*.pyc
|
||||||
|
*sync/
|
||||||
|
Icon?
|
||||||
|
.tags*
|
||||||
|
|
||||||
|
/Flutter/Generated.xcconfig
|
0
ios/Assets/.gitkeep
Normal file
4
ios/Classes/FlutterSmartconfigPlugin.h
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#import <Flutter/Flutter.h>
|
||||||
|
|
||||||
|
@interface FlutterSmartconfigPlugin : NSObject<FlutterPlugin>
|
||||||
|
@end
|
20
ios/Classes/FlutterSmartconfigPlugin.m
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#import "FlutterSmartconfigPlugin.h"
|
||||||
|
|
||||||
|
@implementation FlutterSmartconfigPlugin
|
||||||
|
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
|
||||||
|
FlutterMethodChannel* channel = [FlutterMethodChannel
|
||||||
|
methodChannelWithName:@"flutter_smartconfig"
|
||||||
|
binaryMessenger:[registrar messenger]];
|
||||||
|
FlutterSmartconfigPlugin* instance = [[FlutterSmartconfigPlugin alloc] init];
|
||||||
|
[registrar addMethodCallDelegate:instance channel:channel];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
|
||||||
|
if ([@"getPlatformVersion" isEqualToString:call.method]) {
|
||||||
|
result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
|
||||||
|
} else {
|
||||||
|
result(FlutterMethodNotImplemented);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
21
ios/flutter_smartconfig.podspec
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#
|
||||||
|
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
|
||||||
|
#
|
||||||
|
Pod::Spec.new do |s|
|
||||||
|
s.name = 'flutter_smartconfig'
|
||||||
|
s.version = '0.0.1'
|
||||||
|
s.summary = 'A new flutter plugin project.'
|
||||||
|
s.description = <<-DESC
|
||||||
|
A new flutter plugin project.
|
||||||
|
DESC
|
||||||
|
s.homepage = 'http://example.com'
|
||||||
|
s.license = { :file => '../LICENSE' }
|
||||||
|
s.author = { 'Your Company' => 'email@example.com' }
|
||||||
|
s.source = { :path => '.' }
|
||||||
|
s.source_files = 'Classes/**/*'
|
||||||
|
s.public_header_files = 'Classes/**/*.h'
|
||||||
|
s.dependency 'Flutter'
|
||||||
|
|
||||||
|
s.ios.deployment_target = '8.0'
|
||||||
|
end
|
||||||
|
|
75
lib/flutter_smartconfig.dart
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io' show Platform;
|
||||||
|
|
||||||
|
// Note support only Android
|
||||||
|
// for iOS https://github.com/lou-lan/SmartConfig
|
||||||
|
|
||||||
|
class FlutterSmartconfig {
|
||||||
|
static const platform = const MethodChannel("plugins.flutter.io/flutter_smartconfig");
|
||||||
|
|
||||||
|
static Future<dynamic> configureEsp(
|
||||||
|
{String ssid, String bssid, String password}) async {
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
try {
|
||||||
|
// Change if required.
|
||||||
|
const String deviceCount = "1"; // the expect result count
|
||||||
|
const String broadcast = "1"; // broadcast or multicast
|
||||||
|
const Duration _kLongTimeout = const Duration(seconds: 20);
|
||||||
|
|
||||||
|
final String result =
|
||||||
|
await platform.invokeMethod('startSmartConfig', <String, dynamic>{
|
||||||
|
'ssid': ssid,
|
||||||
|
'bssid': bssid,
|
||||||
|
'pass': password,
|
||||||
|
'deviceCount': deviceCount,
|
||||||
|
'broadcast': broadcast,
|
||||||
|
}).timeout(_kLongTimeout);
|
||||||
|
|
||||||
|
final parsed = json.decode(result);
|
||||||
|
final devices = parsed["devices"];
|
||||||
|
|
||||||
|
return Future<dynamic>(() {
|
||||||
|
return devices;
|
||||||
|
});
|
||||||
|
} on PlatformException catch (e) {
|
||||||
|
return Future<Map<String, String>>(() {
|
||||||
|
throw new PlatformException(
|
||||||
|
code: "Failed to configure: '${e.message}'.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Future<Map<String, String>>(() {
|
||||||
|
throw new PlatformException(code: "only Android is supported");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build.VERSION.SDK_INT >= 28 needs Manifest.permission.ACCESS_COARSE_LOCATION
|
||||||
|
static Future<Map<String, String>> getConnectedWiFiInfo() async {
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
try {
|
||||||
|
String wiFiInfo = await platform.invokeMethod('getConnectedWiFiInfo');
|
||||||
|
final parsed = json.decode(wiFiInfo);
|
||||||
|
|
||||||
|
return Future<Map<String, String>>(() {
|
||||||
|
return {
|
||||||
|
"ssid": parsed["ssid"],
|
||||||
|
"bssid": parsed["bssid"],
|
||||||
|
"is5G": parsed["is5G"]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} on PlatformException catch (e) {
|
||||||
|
return Future<Map<String, String>>(() {
|
||||||
|
throw new PlatformException(
|
||||||
|
code: "Failed to get connected WiFi name: '${e.message}'.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Future<Map<String, String>>(() {
|
||||||
|
throw new PlatformException(code: "only Android is supported");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
56
pubspec.yaml
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
name: flutter_smartconfig
|
||||||
|
description: A new flutter plugin project.
|
||||||
|
version: 0.0.1
|
||||||
|
author:
|
||||||
|
homepage:
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: ">=2.0.0-dev.68.0 <3.0.0"
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
flutter:
|
||||||
|
sdk: flutter
|
||||||
|
|
||||||
|
# For information on the generic Dart part of this file, see the
|
||||||
|
# following page: https://www.dartlang.org/tools/pub/pubspec
|
||||||
|
|
||||||
|
# The following section is specific to Flutter.
|
||||||
|
flutter:
|
||||||
|
# This section identifies this Flutter project as a plugin project.
|
||||||
|
# The androidPackage and pluginClass identifiers should not ordinarily
|
||||||
|
# be modified. They are used by the tooling to maintain consistency when
|
||||||
|
# adding or updating assets for this project.
|
||||||
|
plugin:
|
||||||
|
androidPackage: de.mc8051.fluttersmartconfig
|
||||||
|
pluginClass: FlutterSmartconfigPlugin
|
||||||
|
|
||||||
|
# To add assets to your plugin package, add an assets section, like this:
|
||||||
|
# assets:
|
||||||
|
# - images/a_dot_burr.jpeg
|
||||||
|
# - images/a_dot_ham.jpeg
|
||||||
|
#
|
||||||
|
# For details regarding assets in packages, see
|
||||||
|
# https://flutter.io/assets-and-images/#from-packages
|
||||||
|
#
|
||||||
|
# An image asset can refer to one or more resolution-specific "variants", see
|
||||||
|
# https://flutter.io/assets-and-images/#resolution-aware.
|
||||||
|
|
||||||
|
# To add custom fonts to your plugin package, add a fonts section here,
|
||||||
|
# in this "flutter" section. Each entry in this list should have a
|
||||||
|
# "family" key with the font family name, and a "fonts" key with a
|
||||||
|
# list giving the asset and other descriptors for the font. For
|
||||||
|
# example:
|
||||||
|
# fonts:
|
||||||
|
# - family: Schyler
|
||||||
|
# fonts:
|
||||||
|
# - asset: fonts/Schyler-Regular.ttf
|
||||||
|
# - asset: fonts/Schyler-Italic.ttf
|
||||||
|
# style: italic
|
||||||
|
# - family: Trajan Pro
|
||||||
|
# fonts:
|
||||||
|
# - asset: fonts/TrajanPro.ttf
|
||||||
|
# - asset: fonts/TrajanPro_Bold.ttf
|
||||||
|
# weight: 700
|
||||||
|
#
|
||||||
|
# For details regarding fonts in packages, see
|
||||||
|
# https://flutter.io/custom-fonts/#from-packages
|