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
|