Перенес хранение информации о сессии (токен, din, posid) в базу данных

This commit is contained in:
Ivan Murashov
2017-09-06 17:19:11 +03:00
parent 60090ea437
commit 569c69e268
9 changed files with 162 additions and 127 deletions

View File

@@ -29,9 +29,6 @@ public class MainActivity extends FlutterActivity {
static final String TAG = "Checker.MainActivity";
private static final int START_SCANNER_REQUEST_CODE = 2017;
private static final String PREF_POS_MERCHANT_ID = "pref_pos_merchant_id";
private static final String PREF_DOC_ID = "pref_doc_id";
private static final String PREF_POS_ID = "pref_pos_id";
static final String PREF_API_URL = "prefs_api_token";
static final String PREF_APP_TOKEN = "pres_app_token";
static final String PREF_POS_TOKEN = "pref_pos_token";
@@ -52,34 +49,17 @@ public class MainActivity extends FlutterActivity {
initLocale(this);
mPreferences = getPreferences(Context.MODE_PRIVATE);
Log.d(TAG, "application prefs:");
for(final Map.Entry<String, ?> kv: mPreferences.getAll().entrySet()){
Log.d(TAG, " key = " + kv.getKey() + ", value = " + kv.getValue().toString());
}
mChannel = new MethodChannel(getFlutterView(), "com.dinect.checker/instance_id");
mChannel.setMethodCallHandler(
new MethodCallHandler() {
@Override
public void onMethodCall(MethodCall call, Result result) {
switch (call.method) {
case "saveToken":
Map tokenArguments = call.arguments();
mPreferences.edit().putString(PREF_POS_TOKEN, (String) tokenArguments.get("token")).apply();
break;
case "getToken":
result.success(mPreferences.getString(PREF_POS_TOKEN, null));
break;
case "saveMerchantID":
Map merchantIDArguments = call.arguments();
mPreferences.edit().putString(PREF_POS_MERCHANT_ID, (String) merchantIDArguments.get("merchantID")).apply();
break;
case "getLocale":
result.success(BuildConfig.locale);
break;
case "getMerchantID":
result.success(mPreferences.getString(PREF_POS_MERCHANT_ID, null));
break;
case "startScanner":
final Map arguments = call.arguments();
final int idx = mPreferences.getInt(SCANNER_BACKEND_KEY, 0);
@@ -90,18 +70,7 @@ public class MainActivity extends FlutterActivity {
cameraIntent.putExtra(PREF_POS_TOKEN, (String) arguments.get("token"));
startActivityForResult(cameraIntent, START_SCANNER_REQUEST_CODE);
break;
case "removeKeys":
mPreferences.edit().remove(PREF_POS_TOKEN).apply();
mPreferences.edit().remove(PREF_POS_MERCHANT_ID).apply();
mPreferences.edit().remove(PREF_DOC_ID).apply();
mPreferences.edit().remove(PREF_POS_ID).apply();
result.success(null);
break;
case "getDocID":
int docId = mPreferences.getInt(PREF_DOC_ID, 0) + 1;
mPreferences.edit().putInt(PREF_DOC_ID, docId).apply();
result.success(String.valueOf(docId));
break;
case "isOnline":
boolean online = Utils.isOnline(MainActivity.this);
if (!online) {
@@ -109,14 +78,7 @@ public class MainActivity extends FlutterActivity {
}
result.success(online);
break;
case "getPosID":
String posId = mPreferences.getString(PREF_POS_ID, null);
if (posId == null) {
posId = String.valueOf(System.currentTimeMillis());
}
mPreferences.edit().putString(PREF_POS_ID, posId).apply();
result.success(posId);
break;
default:
result.notImplemented();
break;
@@ -169,53 +131,17 @@ public class MainActivity extends FlutterActivity {
res.updateConfiguration(configuration, res.getDisplayMetrics());
break;
}
}
public void getLocale() {
}
public void handleItemClick() {
}
public void getDocID() {
}
public void removeKeys() {
}
public void startScanner() {
}
public void getInstanceID() {
}
public void saveToken() {
}
public void getToken() {
}
public void getPosID() {
}
public void saveMerchantID() {
}
public void getMerchantID() {
}
public void isOnline() {
}

View File

@@ -17,8 +17,6 @@ extension ZBarSymbolSet: Sequence {
}
}
// TODO: Реализовать окно сканнера в этом контроллере, вместо вызова ZBarReaderViewController
@objc class ScannerViewController: UIViewController, ZBarReaderDelegate {
override func viewDidLoad() {

View File

@@ -25,7 +25,7 @@ faq(BuildContext context, bool returnToScanner) {
// В методе отправляется запрос на удаление токена кассы, очищаются SharedPreferences приложения.
logout(BuildContext context) async {
String token = await platform.invokeMethod('getToken');
String token = await sqliteHelper.getToken();
VoidCallback positiveCalback = () {
if (token != null) {
deleteToken(token).then((response) {
@@ -48,7 +48,7 @@ logout(BuildContext context) async {
}
forceLogout(BuildContext context) async {
String token = await platform.invokeMethod('getToken');
String token = await sqliteHelper.getToken();
deleteToken(token).then((response) {
print(response.body);
platform.invokeMethod('removeKeys').then((result) {
@@ -64,9 +64,9 @@ forceLogout(BuildContext context) async {
/// Может производиться с нескольких экранов (splash, finish_registration).
startScanner(BuildContext context) async {
String token = await platform.invokeMethod('getToken');
String token = await sqliteHelper.getToken();
// Канал ловит вызовы методов из "нативной" части приложения.
// Могут быть вызваны либо logaut либо faq, либо purchase.
// Могут быть вызваны либо logout либо faq, либо purchase.
if (token != null) {
platform.setMethodCallHandler((MethodCall call) async {

82
lib/db.dart Normal file
View File

@@ -0,0 +1,82 @@
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
const String tableSession = "session";
const String columnMerchantID = "merchant_id"; // DIN code, который вводится при авторизации
const String columnToken = "token"; // Токен для pos. Приходит с бэкэнда.
const String columnPosID = "pos_id"; // идентификатор для создания токена на бэке.
const String columnDocID = "doc_id"; // идентификатор, для проведения покупки на бэкенде.
//{
// columnMerchantID: merchantID,
// columnToken: token,
// columnPosID: posID,
// columnDocID: docID
//}
/// База данных, для хранения временных данных (din, token, locale, etc.)
class SqliteHelper {
Database db;
Future open() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, "demo.db");
db = await openDatabase(path, version: 1,
onCreate: (Database db, int version) async {
await db.execute('''create table session (
$columnMerchantID text primary key,
$columnToken text,
$columnPosID text,
$columnDocID integer)''');
});
}
Future insert(String merchantID, String posID, String token) async {
Map session = {
columnMerchantID: merchantID,
columnPosID: posID,
columnToken: token
};
return db.insert(tableSession, session);
}
Future<String> getToken() async {
Map session = await _getSession();
return session != null ? session[columnToken] : null;
}
Future<String> getMerchantID() async {
Map session = await _getSession();
return session != null ? session[columnMerchantID] : null;
}
Future<String> getPosID() async {
Map session = await _getSession();
return session != null ? session[columnPosID] : new DateTime.now().millisecondsSinceEpoch.toString();
}
Future<Map> _getSession() async {
List<Map> maps = await db.query(tableSession, columns: null);
if (maps.length > 0) {
return maps.first;
}
return null;
}
Future clear() async {
return await db.delete(tableSession, where: null);
}
Future close() async => db.close();
}

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:checker/db.dart';
import 'dart:convert'; // Пакет для обработки json с ответом от сервера.
import 'package:checker/common.dart';
@@ -14,12 +15,22 @@ class FinishRegistrationScreen extends StatefulWidget {
class _RegistrationScreenState extends BaseState<FinishRegistrationScreen> {
SqliteHelper helper;
bool _tokenActive = false;
String _merchantID = '';
_RegistrationScreenState() {
helper = new SqliteHelper();
if (textFieldValue == "") {
getSavedMerchantID();
helper.open().then((_){
helper.getMerchantID().then((result) {
setState(() {
_merchantID = result;
print('merchanID: ${_merchantID}');
});
});
});
}
}
@@ -47,10 +58,11 @@ class _RegistrationScreenState extends BaseState<FinishRegistrationScreen> {
// Если нет, то отправляется запрос на проверку статуса токена.
handleTap() async {
if (_tokenActive) {
helper.close();
startScanner(context);
} else {
if (await platform.invokeMethod('isOnline')) {
String token = await platform.invokeMethod('getToken');
String token = await helper.getToken();
checkTokenStatus(token).then((response) {
print(response.body);
@@ -74,16 +86,6 @@ class _RegistrationScreenState extends BaseState<FinishRegistrationScreen> {
style: new TextStyle(color: Colors.black, fontSize: 16.0))]);
}
/// Достаем сохраненный в SharedPreferences merchantID.
getSavedMerchantID() {
platform.invokeMethod('getMerchantID').then((result) {
setState(() {
_merchantID = result;
print('merchanID: ${_merchantID}');
});
});
}
/// Метод возвращает контейнер с текстом сообщения и бэкграундом.
getMessage() {
return new Container(height: _tokenActive ? 72.0 : 108.0, decoration: _getDecorationForMessageField(),

View File

@@ -108,7 +108,7 @@ class PurchaseScreenState<T> extends BaseState<PurchaseScreen> {
if (await platform.invokeMethod('isOnline')) {
String token = await platform.invokeMethod('getToken');
String token = await sqliteHelper.getToken();
var headers = {
'DM-Authorization': 'dmapptoken $appToken',
@@ -198,7 +198,7 @@ class PurchaseScreenState<T> extends BaseState<PurchaseScreen> {
if (!purchaseInProgress) {
purchaseInProgress = true;
String token = await platform.invokeMethod('getToken');
String token = await sqliteHelper.getToken();
platform.invokeMethod('getDocID').then((result) {
String url = user['purchases_url'];

View File

@@ -1,3 +1,4 @@
import 'package:checker/db.dart';
import 'package:checker/finish_registration.dart';
import 'package:flutter/material.dart';
import 'dart:convert'; // Пакет для обработки json с ответом от сервера.
@@ -70,7 +71,12 @@ class _RegistrationScreenState extends BaseState<RegistrationScreen> {
/// Получение от платформы id установки, формирование запроса на получение токена, сохранение токена.
_register() async {
if (await platform.invokeMethod('isOnline')) {
createToken(textFieldValue, await platform.invokeMethod('getPosID')).then((response) {
SqliteHelper helper = new SqliteHelper();
await helper.open();
String posID = await helper.getPosID();
createToken(textFieldValue, posID).then((response) {
setState(() {
error = null;
@@ -80,17 +86,19 @@ class _RegistrationScreenState extends BaseState<RegistrationScreen> {
print(response.body);
Map parsedMap = JSON.decode(response.body);
if (response.statusCode == 201) {
String token = parsedMap['token'];
platform.invokeMethod('saveToken', {'token' : token});
platform.invokeMethod('saveMerchantID', {'merchantID' : textFieldValue});
helper.insert(textFieldValue, posID, parsedMap['token']);
helper.close();
pushRoute(context, new FinishRegistrationScreen());
} else {
helper.close();
setState(() {
error = parsedMap['errors'][0];
});
}
}).catchError((error) {
helper.close();
print(error.toString());
});
}

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:intl/intl.dart';
import 'dart:async';
@@ -9,7 +10,7 @@ import 'network.dart';
import 'consts.dart';
import 'registration.dart';
import 'finish_registration.dart';
import 'strings.dart';
import 'db.dart';
class SplashScreen extends StatelessWidget {
@@ -18,7 +19,7 @@ class SplashScreen extends StatelessWidget {
// Появляется splash screen, проверяется токен.
new Future.delayed(const Duration(milliseconds: 500), () {
platform.invokeMethod("getLocale").then((locale) {
platform.invokeMethod('getLocale').then((locale) {
Intl.defaultLocale = locale;
print(Intl.defaultLocale);
showNextScreen(context);
@@ -49,20 +50,25 @@ class SplashScreen extends StatelessWidget {
/// Запуск следующего экрана приложения.
showNextScreen(BuildContext context) async {
String token = await platform.invokeMethod('getToken');
SqliteHelper helper = new SqliteHelper();
await helper.open();
String token = await helper.getToken();
// В случае, если в приложении отсутствует токен,
// необходимо запустить регистрацию кассы.
if (token == null) {
await helper.close();
pushRoute(context, new RegistrationScreen());
} else {
if (await platform.invokeMethod('isOnline')) {
checkTokenStatus(token).then((statusResponse) {
handleStatusResponse(context, statusResponse);
handleStatusResponse(context, statusResponse, helper);
}).catchError((error) {
helper.close().then((_) {
print(error.toString());
return false;
});
});
}
}
}
@@ -70,15 +76,16 @@ class SplashScreen extends StatelessWidget {
/// Обработка ответа.
/// В случае, если токен был удален может прийти active: false, либо 404.
/// Если токен не активен, попробовать создать его еще раз.
handleStatusResponse(BuildContext context, var statusResponse) async {
handleStatusResponse(BuildContext context, var statusResponse, SqliteHelper helper) async {
int code = statusResponse.statusCode;
print('resp: ${code}');
if (code == 404) {
platform.invokeMethod('removeKeys').then((result) {
print('try to start registration');
helper.clear().then((result) {
helper.close().then((_) {
pushRoute(context, new RegistrationScreen());
});
});
} else {
Map status = JSON.decode(statusResponse.body);
@@ -88,7 +95,7 @@ class SplashScreen extends StatelessWidget {
startScanner(context);
} else {
if (await platform.invokeMethod('isOnline')) {
_createToken(context);
_createToken(context, helper);
}
}
}
@@ -101,24 +108,34 @@ class SplashScreen extends StatelessWidget {
///
/// Если вернулся код 200, значит токен был ранее удален и только что снова создался.
/// Нужно удалить его и направить пользователя на экран регистрации.
_createToken(BuildContext ctx) async {
String merchantID = await platform.invokeMethod('getMerchantID');
String posID = await platform.invokeMethod('getPosID');
_createToken(BuildContext ctx, SqliteHelper helper) async {
String merchantID = await helper.getMerchantID();
String posID = await helper.getPosID();
createToken(merchantID, posID).then((response) {
if (response.statusCode == 409) {
helper.close();
pushRoute(ctx, new FinishRegistrationScreen());
} else if (response.statusCode == 201) {
platform.invokeMethod('removeKeys').then((result) {
Map parsedMap = JSON.decode(result);
deleteToken(parsedMap['token']).then((response) {
print(response.body);
clearToken(response, ctx, helper);
}
}).catchError((error) => print(error.toString()));
}
/// Очищаем бд, делаем запрос на удаление токена.
void clearToken(Response response, BuildContext ctx, SqliteHelper helper) {
helper.clear().then((_) {
Map parsedMap = JSON.decode(response.body);
deleteToken(parsedMap['token']).then((_) {
helper.close();
Navigator.of(ctx).pop(); // Убираем текущий route
pushRoute(ctx, new RegistrationScreen()); // Запускаем регистрацию
}).catchError((error) {
helper.close();
print(error.toString());
});
});
}
}).catchError((error) => print(error.toString()));
}
}

View File

@@ -6,6 +6,8 @@ dependencies:
intl: '>=0.14.0 <0.16.0'
intl_translation: '>=0.14.0 <0.16.0'
sprintf: "^3.0.2"
path_provider: "^0.2.1+1"
sqflite: any
flutter:
sdk: flutter