feat: add Android one-click login with dialog mode

- Integrate ali_auth plugin as local package (previously pub dependency)
- Fix AppCompatActivity ClassNotFoundException via proguard keep rules
- Add dialog popup mode matching iOS style (white background, rounded corners)
- Fix invisible login button by adding blue GradientDrawable background
- Add Airhub logo to authorization dialog via logoImgPath
- Fix auth page not closing after login by calling quitPage() on token success
- Update .gitignore to exclude plugin examples, screenshots, docs and backups

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
repair-agent 2026-02-25 18:05:36 +08:00
parent 679e33428c
commit 12bb369ac1
142 changed files with 10707 additions and 119 deletions

28
airhub_app/.gitignore vendored
View File

@ -43,3 +43,31 @@ app.*.map.json
/android/app/debug
/android/app/profile
/android/app/release
# ali_auth plugin - 不需要提交的文件
packages/ali_auth/example/
packages/ali_auth/screenshots/
packages/ali_auth/doc/
packages/ali_auth/.github/
packages/ali_auth/.metadata
packages/ali_auth/.pubignore
packages/ali_auth/.gitignore
packages/ali_auth/CHANGELOG.md
packages/ali_auth/CHANGELOG-zh.md
packages/ali_auth/CODE_OF_CONDUCT.md
packages/ali_auth/LICENSE
packages/ali_auth/README.md
packages/ali_auth/README_en.md
packages/ali_auth/release.md
packages/ali_auth/test/
# ali_auth 旧备份
packages/ali_auth_backup_*/
# 调试文档和构建脚本
ONECLICK_LOGIN_DEBUG.md
TEST_ONECLICK_LOGIN.md
UPDATE_ALIYUN_SDK.md
build_and_install_ios.sh
build_android_release.sh
rebuild_ios.sh

View File

@ -35,10 +35,16 @@ android {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.getByName("debug")
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
}
dependencies {
// 阿里云一键登录SDK的授权页需要 AppCompatActivity
implementation("androidx.appcompat:appcompat:1.6.1")
}
flutter {
source = "../.."
}

View File

@ -0,0 +1,6 @@
# 阿里云一键登录SDK - 授权页需要 AppCompatActivity
-keep class androidx.appcompat.** { *; }
-keep class com.mobile.auth.** { *; }
-keep class com.cmic.** { *; }
-keep class com.alibaba.sdk.android.** { *; }
-keep class com.alicom.** { *; }

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -1,4 +1,8 @@
PODS:
- ali_auth (1.3.7):
- Flutter
- MJExtension
- SDWebImage
- audio_session (0.0.1):
- Flutter
- Flutter (1.0.0)
@ -10,8 +14,12 @@ PODS:
- just_audio (0.0.1):
- Flutter
- FlutterMacOS
- MJExtension (3.4.2)
- permission_handler_apple (9.3.0):
- Flutter
- SDWebImage (5.21.6):
- SDWebImage/Core (= 5.21.6)
- SDWebImage/Core (5.21.6)
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
@ -20,6 +28,7 @@ PODS:
- FlutterMacOS
DEPENDENCIES:
- ali_auth (from `.symlinks/plugins/ali_auth/ios`)
- audio_session (from `.symlinks/plugins/audio_session/ios`)
- Flutter (from `Flutter`)
- flutter_blue_plus_darwin (from `.symlinks/plugins/flutter_blue_plus_darwin/darwin`)
@ -29,7 +38,14 @@ DEPENDENCIES:
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/darwin`)
SPEC REPOS:
trunk:
- MJExtension
- SDWebImage
EXTERNAL SOURCES:
ali_auth:
:path: ".symlinks/plugins/ali_auth/ios"
audio_session:
:path: ".symlinks/plugins/audio_session/ios"
Flutter:
@ -48,12 +64,15 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/webview_flutter_wkwebview/darwin"
SPEC CHECKSUMS:
ali_auth: fe9a6188a90eb39227f3674c05a71383ac4ec6a2
audio_session: 9bb7f6c970f21241b19f5a3658097ae459681ba0
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
flutter_blue_plus_darwin: 20a08bfeaa0f7804d524858d3d8744bcc1b6dbc3
image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326
just_audio: 4e391f57b79cad2b0674030a00453ca5ce817eed
MJExtension: e97d164cb411aa9795cf576093a1fa208b4a8dd8
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
SDWebImage: 1bb6a1b84b6fe87b972a102bdc77dd589df33477
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
webview_flutter_wkwebview: 8ebf4fded22593026f7dbff1fbff31ea98573c8d

View File

@ -44,12 +44,27 @@ class ApiClient {
}
/// POST data
/// path http:// https:// URL 使
Future<dynamic> post(
String path, {
dynamic data,
}) async {
final response = await _request(
() => _dio.post(path, data: data),
() {
// URL使 Options baseUrl
if (path.startsWith('http://') || path.startsWith('https://')) {
return _dio.post(
path,
data: data,
options: Options(
headers: {'Content-Type': 'application/json'},
// 使 baseUrl Dio 使
extra: {'useFullUrl': true},
),
);
}
return _dio.post(path, data: data);
},
);
return response;
}

View File

@ -1,7 +1,10 @@
class ApiConfig {
/// IP
///
static const String baseUrl = 'http://192.168.124.8:8000';
/// HTTPS
static const String authBaseUrl = 'https://qiyuan-rtc-api.airlabs.art';
/// App API
static const String apiPrefix = '/api/v1';
@ -13,4 +16,7 @@ class ApiConfig {
/// URL
static String get fullBaseUrl => '$baseUrl$apiPrefix';
/// URL
static String get fullAuthBaseUrl => '$authBaseUrl$apiPrefix';
}

View File

@ -1,9 +1,7 @@
import 'dart:async';
import 'package:flutter/foundation.dart' show debugPrint, kIsWeb;
import 'package:riverpod_annotation/riverpod_annotation.dart';
// Web 使 stubali_auth Dart
import 'phone_auth_service_stub.dart';
import 'package:ali_auth/ali_auth.dart';
part 'phone_auth_service.g.dart';
@ -19,13 +17,132 @@ PhoneAuthService phoneAuthService(Ref ref) {
return PhoneAuthService();
}
///
const _terminalErrorCodes = {
'600002', //
'600004', //
'600005', //
'600007', // SIM卡
'600008', //
'600009', //
'600010', //
'600011', // token失败
'600012', //
'600013', //
'600014', //
'600015', //
'600017', // AppID/Appkey解析失败
'600018', // SDK
'600021', //
'600023', //
'600025', //
'600026', //
'500000', //
'500001', //
'500003', //
};
class PhoneAuthService {
bool _initialized = false;
String? _lastError;
/// initSdk EventChannel
Completer<void>? _initCompleter;
/// login EventChannel token
Completer<String?>? _loginCompleter;
///
final List<String> _eventLog = [];
/// UI
String? get lastError => _lastError;
/// EventChannel
void _handleEvent(dynamic event) {
debugPrint('[AliAuth] event: $event');
final code = event['code'] as String?;
if (code == null) return;
_eventLog.add('$code:${event['msg'] ?? ''}');
// ========== ==========
if (code == '600000') {
final token = event['data'] as String?;
if (token != null && token.isNotEmpty) {
debugPrint('[AliAuth] 登录成功,获取到 token');
// loadingAndroid原生端未自动关闭
AliAuth.quitPage();
if (_loginCompleter != null && !_loginCompleter!.isCompleted) {
_loginCompleter!.complete(token);
}
}
return;
}
// ========== ==========
if (code == '700000') {
_lastError = '用户取消登录';
debugPrint('[AliAuth] $_lastError');
if (_loginCompleter != null && !_loginCompleter!.isCompleted) {
_loginCompleter!.complete(null);
}
return;
}
// ========== ==========
if (code == '700001') {
_lastError = '切换其他方式';
debugPrint('[AliAuth] $_lastError');
if (_loginCompleter != null && !_loginCompleter!.isCompleted) {
_loginCompleter!.complete(null);
}
return;
}
// ========== ==========
if (code == '700020') {
debugPrint('[AliAuth] 授权页已销毁');
if (_loginCompleter != null && !_loginCompleter!.isCompleted) {
_lastError ??= '授权页已关闭';
_loginCompleter!.complete(null);
}
return;
}
// ========== ==========
if (_terminalErrorCodes.contains(code)) {
_lastError = '${event['msg'] ?? '错误码$code'}';
debugPrint('[AliAuth] 终止性错误: $_lastError');
if (_initCompleter != null && !_initCompleter!.isCompleted) {
_initCompleter!.completeError(_lastError!);
}
if (_loginCompleter != null && !_loginCompleter!.isCompleted) {
_loginCompleter!.complete(null);
}
return;
}
// ========== ==========
if (code == '600016') {
debugPrint('[AliAuth] 预取号成功SDK就绪');
if (_initCompleter != null && !_initCompleter!.isCompleted) {
_initCompleter!.complete();
}
return;
}
// ========== ==========
// 500004: SDK版本信息
// 600001:
// 600024:
// 700002: SDK返回600000或错误
// 700003:
// 700004:
// 700005:
// 700006~700010:
debugPrint('[AliAuth] 中间事件 $code: ${event['msg'] ?? ''}');
}
/// SDK
Future<void> init() async {
debugPrint('[AliAuth] init() called, _initialized=$_initialized, kIsWeb=$kIsWeb');
@ -35,16 +152,91 @@ class PhoneAuthService {
return;
}
_initCompleter = Completer<void>();
try {
await AliAuth.initSdk(
// EventChannel initSdk
// iOS initSdk _eventSink nil
AliAuth.loginListen(onEvent: _handleEvent);
// await initSdk iOS MethodChannel
// EventChannel
// isDelay:true +
AliAuth.initSdk(
AliAuthModel(
PhoneAuthConfig.androidSk,
PhoneAuthConfig.iosSk,
isDebug: true,
isDelay: true,
autoQuitPage: true,
pageType: PageType.fullPort,
// ========== iOS ==========
pageType: PageType.dialogPort,
dialogWidth: 300,
dialogHeight: 340,
dialogCornerRadiusArray: [12, 12, 12, 12],
dialogAlpha: 0.5,
tapAuthPageMaskClosePage: true,
// ========== ==========
navHidden: true,
navReturnHidden: true,
// ========== Logo ==========
logoHidden: false,
logoImgPath: 'assets/www/logo.png',
logoWidth: 60,
logoHeight: 60,
logoOffsetY: 20,
// ========== ==========
numberColor: '#333333',
numFieldOffsetY: 95,
// ========== Slogan ==========
sloganHidden: true,
// ========== ==========
logBtnText: '本机号码一键登录',
logBtnTextColor: '#FFFFFF',
logBtnWidth: 250,
logBtnHeight: 44,
logBtnOffsetY: 140,
// ========== ==========
switchAccText: '其他方式登录',
switchAccTextColor: '#999999',
switchOffsetY: 195,
// ========== ==========
privacyState: true,
privacyBefore: '我已阅读并同意',
privacyEnd: '',
vendorPrivacyPrefix: '',
vendorPrivacySuffix: '',
protocolOneName: '用户协议',
protocolOneURL: 'https://qiyuan-rtc-api.airlabs.art/agreement/',
protocolTwoName: '隐私政策',
protocolTwoURL: 'https://qiyuan-rtc-api.airlabs.art/privacy/',
privacyOffsetY_B: 15,
// ========== ==========
pageBackgroundPath: '',
backgroundColor: '#FFFFFF',
pageBackgroundRadius: 12,
isHiddenCustom: true,
),
);
// EventChannel 600016
await _initCompleter!.future.timeout(
const Duration(seconds: 10),
onTimeout: () {
throw TimeoutException(
'初始化超时(10s) events=${_eventLog.join(",")}');
},
);
_initialized = true;
_lastError = null;
debugPrint('[AliAuth] SDK 初始化成功');
@ -52,6 +244,8 @@ class PhoneAuthService {
_initialized = false;
_lastError = 'SDK初始化失败: $e';
debugPrint('[AliAuth] $_lastError');
} finally {
_initCompleter = null;
}
}
@ -67,34 +261,25 @@ class PhoneAuthService {
return null;
}
final completer = Completer<String?>();
_loginCompleter = Completer<String?>();
AliAuth.loginListen(onEvent: (event) {
debugPrint('[AliAuth] loginListen event: $event');
final code = event['code'] as String?;
if (code == '600000' && event['data'] != null) {
if (!completer.isCompleted) {
completer.complete(event['data'] as String);
}
} else if (code == '700000' || code == '700001') {
_lastError = '用户取消';
if (!completer.isCompleted) {
completer.complete(null);
}
} else if (code != null && code.startsWith('6') && code != '600000') {
_lastError = '错误码$code: ${event['msg']}';
debugPrint('[AliAuth] $_lastError');
if (!completer.isCompleted) {
completer.complete(null);
}
// login()
// await iOS MethodChannel
try {
debugPrint('[AliAuth] 调用 AliAuth.login() 触发登录');
AliAuth.login();
} catch (e) {
_lastError = '调用登录失败: $e';
debugPrint('[AliAuth] $_lastError');
if (!_loginCompleter!.isCompleted) {
_loginCompleter!.complete(null);
}
});
}
return completer.future.timeout(
const Duration(seconds: 30),
return _loginCompleter!.future.timeout(
const Duration(seconds: 15),
onTimeout: () {
_lastError = '请求超时(30s)';
_lastError = '登录超时(15s) events=${_eventLog.join(",")}';
debugPrint('[AliAuth] $_lastError');
return null;
},

View File

@ -2,6 +2,7 @@
class AliAuth {
static Future<void> initSdk(dynamic model) async {}
static void loginListen({required Function(Map<String, dynamic>) onEvent}) {}
static Future<dynamic> login({int timeout = 5000}) async {}
}
class AliAuthModel {

View File

@ -1,5 +1,6 @@
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../../../../core/network/api_client.dart';
import '../../../../core/network/api_config.dart';
import '../../domain/entities/auth_tokens.dart';
import '../../domain/entities/user.dart';
@ -44,8 +45,9 @@ class AuthRemoteDataSourceImpl implements AuthRemoteDataSource {
@override
Future<({User user, AuthTokens tokens, bool isNewUser})> tokenLogin(
String token) async {
// 使 HTTPS
final data = await _apiClient.post(
'/auth/phone-login/',
'${ApiConfig.fullAuthBaseUrl}/auth/phone-login/',
data: {'token': token},
);
return _parseLoginResponse(data as Map<String, dynamic>);

View File

@ -0,0 +1,4 @@
include: package:flutter_lints/flutter.yaml
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

View File

@ -0,0 +1,8 @@
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures

View File

@ -0,0 +1,95 @@
apply plugin: 'com.android.library'
group 'com.sean.rao.ali_auth'
version '1.3.1'
buildscript {
repositories {
mavenLocal()
// google()
// jcenter()
// JitPack https://jitpack.io
maven { url 'https://jitpack.io' }
maven { url 'https://download.flutter.io'}
maven { url 'https://maven.aliyun.com/repository/public' }
maven { url 'https://maven.aliyun.com/repository/google' }
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.3'
}
}
rootProject.allprojects {
repositories {
mavenLocal()
// google()
// jcenter()
// JitPack https://jitpack.io
maven { url 'https://jitpack.io' }
maven { url 'https://download.flutter.io'}
maven { url 'https://maven.aliyun.com/repository/public' }
maven { url 'https://maven.aliyun.com/repository/google' }
}
}
android {
if (project.android.hasProperty("namespace")) {
namespace = "com.sean.rao.ali_auth"
}
compileSdkVersion 34
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
defaultConfig {
minSdkVersion 21
}
aaptOptions {
noCompress "mov" //aapt压缩的文件后缀
}
buildTypes {
release {
debuggable false
// minifyEnabled true
proguardFile file('proguard-rules.pro')
zipAlignEnabled false
multiDexEnabled true
}
debug {
// minifyEnabled false
zipAlignEnabled false
multiDexEnabled true
}
}
dependencies {
implementation "androidx.appcompat:appcompat:1.7.1"
// fastjson库
implementation 'com.alibaba.fastjson2:fastjson2:2.0.51.android5'
// implementation 'com.google.code.gson:gson:2.10.1'
// implementation 'com.alibaba:fastjson:1.2.83'
implementation files("libs/auth_number_product-${authLibVersion}-release.aar")
implementation files("libs/logger-${loggerVersion}-release.aar")
implementation files("libs/main-${mainVersion}-release.aar")
// https://github.com/getActivity/Toaster
implementation 'com.github.getActivity:Toaster:12.2'
// uc的crash收集库
// implementation 'com.ucweb.wpk:crashsdk:3.2.2.2'
}
}

View File

@ -0,0 +1,107 @@
apply plugin: 'com.android.library'
group 'com.sean.rao.ali_auth'
version '1.3.7'
buildscript {
repositories {
mavenLocal()
mavenCentral()
// google()
// jcenter()
maven { url 'https://dl.bintray.com/jetbrains/anko'}
maven { url 'https://download.flutter.io'}
maven { url 'https://maven.aliyun.com/repository/public' }
maven { url 'https://maven.aliyun.com/repository/google' }
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.3'
}
}
// , moudle的dir
def getCurrentProjectDir() {
String result = ""
rootProject.allprojects { project ->
if (project.properties.get("identityPath").toString() == ":ali_auth") { // flutter的约定, module名是插件名, :gradle的约定. project前加:
result = project.properties.get("projectDir").toString()
}
}
return result
}
rootProject.allprojects {
def dir = getCurrentProjectDir()
repositories {
mavenLocal()
mavenCentral()
// google()
// jcenter()
maven { url 'https://dl.bintray.com/jetbrains/anko'}
maven { url 'https://download.flutter.io'}
maven { url 'https://maven.aliyun.com/repository/public' }
maven { url 'https://maven.aliyun.com/repository/google' }
//
flatDir {
dirs project(':ali_auth').file('libs')
}
}
}
android {
if (project.android.hasProperty("namespace")) {
namespace = "com.sean.rao.ali_auth"
}
compileSdkVersion 35
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
minSdkVersion 21
}
aaptOptions {
noCompress "mov" //aapt压缩的文件后缀
}
buildTypes {
release {
debuggable false
// minifyEnabled true
proguardFile file('proguard-rules.pro')
zipAlignEnabled false
multiDexEnabled true
}
debug {
// minifyEnabled false
zipAlignEnabled false
multiDexEnabled true
}
}
}
dependencies {
implementation "androidx.appcompat:appcompat:1.3.0"
// fastjson库
implementation "com.alibaba.fastjson2:fastjson2:2.0.51.android5"
// implementation 'com.google.code.gson:gson:2.10.1'
// implementation 'com.alibaba:fastjson:1.2.83'
implementation(name: "auth_number_product-${authLibVersion}-release", ext:'aar')
implementation(name: "logger-${loggerVersion}-release", ext:'aar')
implementation(name: "main-${mainVersion}-release", ext:'aar')
// https://github.com/getActivity/Toaster
// implementation 'com.github.getActivity:Toaster:12.2'
// uc的crash收集库
// implementation 'com.ucweb.wpk:crashsdk:3.2.2.2'
}

View File

@ -0,0 +1,21 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
android.injected.testOnly=false
authLibVersion=2.14.19
loggerVersion=2.2.2
mainVersion=2.2.3

View File

@ -0,0 +1,3 @@
mvn deploy:deploy-file -Dfile=sdk.aar -Durl="file://." -DgroupId="com.pgyer" -DartifactId="sdk" -Dversion="3.0.9"
mvn deploy:deploy-file -Dfile=sdk.aar -Durl="file://." -DgroupId="com.mobile.auth" -DartifactId="auth-number-product" -Dversion="2.14.14"

View File

@ -0,0 +1,10 @@
# 感谢 ZengJo的贡献
-keep class android.app.ActivityThread {*;}
-keep class android.os.SystemProperties {*;}
-keep class com.mobile.auth.** { *; }
-keep class com.alibaba.sdk.android.* { *; }
-keep class com.alicom.* { *; }
-keep class com.taobao.* { *; }
-keep class androidx.appcompat.** { *; }
-keep class com.cmic.** { *; }

View File

@ -0,0 +1 @@
rootProject.name = 'ali_auth'

View File

@ -0,0 +1,78 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.sean.rao.ali_auth">
<!--允许访问网络状态的权限-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--允许修改网络状态的权限-->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<!--允许修改 WIFI 状态的权限。-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<!--允许访问 WIFI 状态的权限-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<!-- 跳转原生调用flutter时页面的样式 -->
<application
android:usesCleartextTraffic="true"
tools:targetApi="m">
<activity
android:name="io.flutter.embedding.android.FlutterActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:theme="@android:style/Theme.NoTitleBar"
android:windowSoftInputMode="adjustResize"
android:usesCleartextTraffic="true"/>
<!--协议页面webview-->
<activity
android:name="com.mobile.auth.gatewayauth.activity.AuthWebVeiwActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
tools:replace="android:theme"
android:exported="false"
android:launchMode="singleTop"
android:screenOrientation="behind"
android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
<!--联通电信授权页-->
<activity
android:name="com.mobile.auth.gatewayauth.LoginAuthActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
tools:replace="android:configChanges"
android:exported="false"
android:launchMode="singleTop"
android:screenOrientation="behind"
android:theme="@style/authsdk_activity_dialog"/>
<!--移动授权页-->
<activity
android:name="com.cmic.sso.sdk.activity.LoginAuthActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
tools:replace="android:configChanges"
android:exported="false"
android:launchMode="singleTask"
android:screenOrientation="behind"
android:theme="@style/authsdk_activity_dialog" />
<!--二次弹窗-->
<activity
android:name="com.mobile.auth.gatewayauth.PrivacyDialogActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
tools:replace="android:configChanges"
android:exported="false"
android:launchMode="singleTop"
android:screenOrientation="behind"
android:theme="@style/authsdk_activity_dialog"/>
<!--适配华为刘海屏-->
<meta-data
android:name="android.notch_support"
android:value="true"/>
<!--适配小米刘海屏-->
<meta-data
android:name="notch.config"
android:value="portrait|landscape" />
</application>
</manifest>

View File

@ -0,0 +1,306 @@
package com.sean.rao.ali_auth;
import android.app.Activity;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.os.Build;
import android.util.Log;
import androidx.annotation.NonNull;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.mobile.auth.gatewayauth.PhoneNumberAuthHelper;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterEngineCache;
import io.flutter.embedding.engine.dart.DartExecutor;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.EventChannel;
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 com.sean.rao.ali_auth.common.LoginParams;
import com.sean.rao.ali_auth.login.OneKeyLoginPublic;
import com.sean.rao.ali_auth.utils.UtilTool;
/** AliAuthPlugin */
public class AliAuthPlugin extends FlutterActivity implements FlutterPlugin, ActivityAware, MethodCallHandler, EventChannel.StreamHandler {
private static final String TAG = "ali_auth 一键登录插件";
private Context mContext;
private Activity mActivity;
/// The MethodChannel that will the communication between Flutter and native Android
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
/// when the Flutter Engine is detached from the Activity
private MethodChannel channel;
private FlutterEngine flutterEngine;
private FlutterEngineCache flutterEngineCache;
public static EventChannel.EventSink _events;
private static final String METHOD_CHANNEL = "ali_auth";
private static final String EVENT_CHANNEL = "ali_auth/event";
private ConnectivityManager.NetworkCallback callback;
/**
* 延时登录
*/
private OneKeyLoginPublic oneKeyLoginPublic;
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), METHOD_CHANNEL);
// 原生通讯
EventChannel eventChannel = new EventChannel(flutterPluginBinding.getBinaryMessenger(), EVENT_CHANNEL);
eventChannel.setStreamHandler(this);
// // Activity
// flutterView.getLookupKeyForAsset("images/ic_launcher.png");
// // Fragment
// (FlutterView) getView().getLookupKeyForAsset("images/ic_launcher.png");
// // 通用
// FlutterMain.getLookupKeyForAsset("images/ic_launcher.png");
// 创建flutter发动机
flutterEngineCache = FlutterEngineCache.getInstance();
channel.setMethodCallHandler(this);
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
switch (call.method){
case "getPlatformVersion":
result.success("当前Android信息" + android.os.Build.VERSION.RELEASE);
break;
case "getCurrentCarrierName":
// CMCC(移动)CUCC(联通)CTCC(电信)
String carrierName = "获取失败";
if (oneKeyLoginPublic == null) {
PhoneNumberAuthHelper phoneNumberAuthHelper = PhoneNumberAuthHelper.getInstance(mActivity, null);
carrierName = phoneNumberAuthHelper.getCurrentCarrierName();
} else {
carrierName = oneKeyLoginPublic.getCurrentCarrierName();
}
if (carrierName.contains("CMCC")) {
carrierName = "中国移动";
} else if (carrierName.contains("CUCC")) {
carrierName = "中国联通";
} else if (carrierName.contains("CTCC")) {
carrierName = "中国电信";
}
result.success(carrierName);
break;
case "initSdk":
JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(call.arguments));
if (_events == null) {
result.error("500001", "请先对插件进行监听!", null);
} else {
boolean isDelay = jsonObject.getBoolean("isDelay");
/// 判断是否初始化过或者是否是同步登录如果是将进行再次初始化
if (oneKeyLoginPublic == null || !isDelay) {
try {
oneKeyLoginPublic = new OneKeyLoginPublic(mActivity, _events, call.arguments);
} catch (Exception e) {
Log.e(TAG, "initSdk 初始化异常: " + e.getMessage(), e);
_events.success(UtilTool.resultFormatData("500000", "SDK初始化异常: " + e.getMessage(), ""));
}
}
result.success(null);
}
break;
case "login":
if (oneKeyLoginPublic != null) {
oneKeyLoginPublic.startLogin(LoginParams.jsonObject.getIntValue("timeout", 5000));
} else {
_events.success(UtilTool.resultFormatData("500003", null, ""));
}
result.success(null);
break;
case "checkEnvAvailable":
oneKeyLoginPublic.checkEnvAvailable(2);
result.success(null);
break;
case "queryCheckBoxIsChecked":
boolean status = oneKeyLoginPublic.queryCheckBoxIsChecked();
result.success(status);
break;
case "setCheckboxIsChecked":
boolean checked = oneKeyLoginPublic.setCheckBoxIsChecked();
result.success(checked);
break;
case "checkCellularDataEnable":
isNetEnabled(mContext, result);
break;
case "quitPage":
oneKeyLoginPublic.quitPage();
result.success(null);
break;
case "hideLoading":
oneKeyLoginPublic.hideLoading();
result.success(null);
break;
case "openPage":
if (flutterEngine == null) {
flutterEngine = new FlutterEngine(mContext);
}
//指定想要跳转的flutter页面 这里要和下图对应上 记住他
flutterEngine.getNavigationChannel().setInitialRoute(call.argument("pageRoute"));
flutterEngine.getDartExecutor().executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault());
//这里做一个缓存 可以在适当的地方执行他 比如MyApp里 或者未跳转flutterr之前 在flutter页面执行前预加载
//缓存可以缓存好多个 以不同的的id区分
flutterEngineCache.put("default_engine_id", flutterEngine);
//上面的代码一般在执行跳转操作之前调用 这样可以预加载页面 是的跳转的时候速度加快
//跳转页面
mActivity.startActivity(FlutterActivity.withCachedEngine("default_engine_id").build(mContext));
result.success("调用成功!");
break;
default:
result.notImplemented();
}
}
@Override
public void onListen(Object o, EventChannel.EventSink eventSink) {
Log.d(TAG, "listen 初始化完毕!");
String version = PhoneNumberAuthHelper.getVersion();
eventSink.success(UtilTool.resultFormatData("500004", String.format("插件启动监听成功, 当前SDK版本: %s", version), ""));
if( _events == null ){
_events = eventSink;
}
}
@Override
public void onCancel(Object o) {
if( _events != null){
_events = null;
}
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
channel.setMethodCallHandler(null);
}
@Override
public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
mActivity = binding.getActivity();
mContext = mActivity.getBaseContext();
}
@Override
public void onDetachedFromActivityForConfigChanges() {
}
@Override
public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {
}
@Override
public void onDetachedFromActivity() {
if( _events != null){
_events.endOfStream();
}
mActivity = null;
}
/**
* 判断移动网络是否开启
*
* @param context
* @return
*/
public void isNetEnabled(Context context, @NonNull Result result) {
JSONObject resultObject = new JSONObject();
resultObject.put("code", 0);
resultObject.put("msg", "未检测到网络!");
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
// callback = new ConnectivityManager.NetworkCallback() {
// // 可用网络接入
// public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
// // 一般在此处获取网络类型然后判断网络类型就知道时哪个网络可以用connected
// System.out.println(network);
// System.out.println(networkCapabilities);
// }
// // 网络断开
// public void onLost(Network network) {
// System.out.println(network);
// // 如果通过ConnectivityManager#getActiveNetwork()返回null表示当前已经没有其他可用网络了
// }
// };
// registerNetworkCallback(context);
Network network =cm.getActiveNetwork();
if(network!=null){
NetworkCapabilities nc=cm.getNetworkCapabilities(network);
if(nc!=null){
resultObject.put("code", 1);
if(nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)){ // WIFI
resultObject.put("msg", "WIFI网络已开启");
}else if(nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)){ // 移动数据
resultObject.put("msg", "蜂窝网络已开启");
}
}
}
} else {
NetworkInfo mWiFiNetworkInfo = cm.getActiveNetworkInfo();
if (mWiFiNetworkInfo != null) {
resultObject.put("code", 1);
if (mWiFiNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI) { // WIFI
resultObject.put("msg", "WIFI网络已开启");
} else if (mWiFiNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE) { // 移动数据
resultObject.put("msg", "蜂窝网络已开启");
}
}
}
result.success(resultObject);
}
// 注册回调
private void registerNetworkCallback(Context context) {
ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
NetworkRequest.Builder builder = new NetworkRequest.Builder();
builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
cm.registerNetworkCallback(builder.build(), callback);
}
}
// 注销回调
private void unregisterNetworkCallback(Context context) {
ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
cm.unregisterNetworkCallback(callback);
}
}
/**
* 判断移动网络是否连接成功
*
* @param context
* @return
*/
public boolean isNetContected(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if (info != null && info.isConnected()) {
Log.i(TAG, "移动网络连接成功");
return true;
}
Log.i(TAG, "移动网络连接失败");
return false;
}
}

View File

@ -0,0 +1,73 @@
package com.sean.rao.ali_auth.auth;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.Toolbar;
import com.mobile.auth.gatewayauth.Constant;
import com.sean.rao.ali_auth.R;
import org.jetbrains.annotations.Nullable;
/**
* @ProjectName: NumberAuthSDK_Standard_Android
* @Package: com.aliqin.mytel.auth
* @ClassName: CustomWebView
* @Description: 自定义协议展示页
* @Author: liuqi
* @CreateDate: 2021/3/25 4:04 PM
* @Version: 1.0
*/
public class CustomWebViewActivity extends Activity {
private WebView mWebView;
private Toolbar mToolbar;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_custom_web);
String mUrl = getIntent().getStringExtra(Constant.PROTOCOL_WEB_VIEW_URL);
String mName = getIntent().getStringExtra(Constant.PROTOCOL_WEB_VIEW_NAME);
setRequestedOrientation(
getIntent().getIntExtra(Constant.PROTOCOL_WEB_VIEW_ORIENTATION, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT));
mWebView = findViewById(R.id.webView);
mToolbar = findViewById(R.id.toolbar);
// mToolbar.setSubtitle(mName);
initWebView();
mWebView.loadUrl(mUrl);
}
@SuppressLint("SetJavaScriptEnabled")
private void initWebView() {
WebSettings wvSettings = mWebView.getSettings();
// 是否阻止网络图像
wvSettings.setBlockNetworkImage(false);
// 是否阻止网络请求
wvSettings.setBlockNetworkLoads(false);
// 是否加载JS
wvSettings.setJavaScriptEnabled(true);
wvSettings.setJavaScriptCanOpenWindowsAutomatically(true);
//覆盖方式启动缓存
wvSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
// 使用广泛视窗
wvSettings.setUseWideViewPort(true);
wvSettings.setLoadWithOverviewMode(true);
wvSettings.setDomStorageEnabled(true);
//是否支持缩放
wvSettings.setBuiltInZoomControls(false);
wvSettings.setSupportZoom(false);
//不显示缩放按钮
wvSettings.setDisplayZoomControls(false);
wvSettings.setAllowFileAccess(true);
wvSettings.setDatabaseEnabled(true);
//缓存相关
// wvSettings.setAppCacheEnabled(true);
wvSettings.setDomStorageEnabled(true);
wvSettings.setDatabaseEnabled(true);
}
}

View File

@ -0,0 +1,145 @@
package com.sean.rao.ali_auth.auth;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import org.jetbrains.annotations.Nullable;
import com.mobile.auth.gatewayauth.PhoneNumberAuthHelper;
import com.mobile.auth.gatewayauth.PreLoginResultListener;
import com.mobile.auth.gatewayauth.ResultCode;
import com.mobile.auth.gatewayauth.TokenResultListener;
import com.mobile.auth.gatewayauth.model.TokenRet;
import com.sean.rao.ali_auth.utils.ExecutorManager;
public class NumberAuthActivity extends Activity {
private static final String TAG = NumberAuthActivity.class.getSimpleName();
private PhoneNumberAuthHelper mAuthHelper;
private TokenResultListener mVerifyListener;
private Button mAuthButton;
private EditText mNumberEt;
private String phoneNumber;
private ProgressDialog mProgressDialog;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_auth);
// mAuthButton = findViewById(R.id.auth_btn);
// mNumberEt = findViewById(R.id.et_number);
mAuthButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
phoneNumber = mNumberEt.getText().toString();
//判断手机号是否合法
if (!TextUtils.isEmpty(phoneNumber)) {
showLoadingDialog("正在进行本机号码校验");
numberAuth(5000);
}
}
});
sdkInit();
accelerateVerify(5000);
}
private void sdkInit() {
mVerifyListener = new TokenResultListener() {
@Override
public void onTokenSuccess(String s) {
Log.i(TAG, "获取token成功" + s);
try {
TokenRet pTokenRet = TokenRet.fromJson(s);
if (ResultCode.CODE_SUCCESS.equals(pTokenRet.getCode()) && !TextUtils.isEmpty(pTokenRet.getToken())) {
getResultWithToken(pTokenRet.getToken(), phoneNumber);
}
mAuthHelper.setAuthListener(null);
} catch (Exception e) {
e.fillInStackTrace();
}
}
@Override
public void onTokenFailed(final String s) {
Log.i(TAG, "获取token失败" + s);
NumberAuthActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
hideLoadingDialog();
setResult(2);
finish();
}
});
mAuthHelper.setAuthListener(null);
}
};
mAuthHelper = PhoneNumberAuthHelper.getInstance(getApplicationContext(), mVerifyListener);
}
/**
* 加速校验
* 进入输入手机号页面调用此接口用户输入完手机号点击确定可以更快的获取token
* @param timeout
*/
public void accelerateVerify(int timeout) {
mAuthHelper.accelerateVerify(timeout, new PreLoginResultListener() {
@Override
public void onTokenSuccess(String vendor) {
//成功时返回运营商简称
Log.i(TAG, "accelerateVerify" + vendor);
}
@Override
public void onTokenFailed(String vendor, String errorMsg) {
Log.e(TAG, "accelerateVerify" + vendor + " " + errorMsg);
}
});
}
public void numberAuth(int timeout) {
mAuthHelper.setAuthListener(mVerifyListener);
mAuthHelper.getVerifyToken(timeout);
}
public void getResultWithToken(final String token, final String phoneNumber) {
ExecutorManager.run(new Runnable() {
@Override
public void run() {
// final String result = verifyNumber(token, phoneNumber);
NumberAuthActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
hideLoadingDialog();
Intent pIntent = new Intent();
pIntent.putExtra("result", phoneNumber);
setResult(1, pIntent);
finish();
}
});
}
});
}
public void showLoadingDialog(String hint) {
if (mProgressDialog == null) {
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
}
mProgressDialog.setMessage(hint);
mProgressDialog.setCancelable(true);
mProgressDialog.show();
}
public void hideLoadingDialog() {
if (mProgressDialog != null) {
mProgressDialog.dismiss();
}
}
}

View File

@ -0,0 +1,213 @@
package com.sean.rao.ali_auth.common;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import android.util.LruCache;
import com.nirvana.tools.core.CryptUtil;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
/**
* @Package: com.aliqin.mytel
* @ClassName: CacheManage
* @Description: 类作用描述
* @Author: liuqi
* @CreateDate: 2021/5/13 9:55 AM
* @Version: 1.0
*/
public class CacheManage {
Context context;
private LruCache<String, Bitmap> mBitmapLruCache = null;
private ConcurrentHashMap<String, String> mFilePathCache = null;
private final static String CACHE_FILE_DIR = "ALSDK_FILE_CACHE";
private final static String CACHE_COVER_DIR = "ALSDK_COVER_CACHE";
public CacheManage(Context context) {
this.context = context;
final File dir = new File(context.getCacheDir(), CACHE_FILE_DIR);
if (dir.exists()) {
mFilePathCache = new ConcurrentHashMap<String, String>();
File[] listFiles = dir.listFiles();
if (null != listFiles && listFiles.length > 0) {
for (File file : listFiles) {
String fileName = file.getName();
String key = fileName.substring(0, fileName.lastIndexOf("."));
mFilePathCache.put(key, file.getAbsolutePath());
}
}
}
}
/**
* 创建缓存文件
*
* @param url
* @param ext 文件后缀
* @return
*/
public File createCacheFile(String url, String ext) {
final File dir = new File(context.getCacheDir(), CACHE_FILE_DIR);
if (!dir.exists()) {
dir.mkdirs();
}
String key = url;
try {
key = CryptUtil.md5Hex(url);
} catch (Exception e) {
key = url;
}
return new File(dir, key + ext);
}
/**
* 获取bitma内存缓存
*
* @return
*/
public LruCache<String, Bitmap> getBitmapLruCache() {
if (mBitmapLruCache == null) {
long mTotalSize = Runtime.getRuntime().totalMemory();
mBitmapLruCache = new LruCache<>((int)(mTotalSize / 5));
}
return mBitmapLruCache;
}
/**
* 获取文件缓存
*
* @param url
* @return
*/
public String getCacheFilePath(String url) {
String key = url;
try {
key = CryptUtil.md5Hex(url);
} catch (Exception e) {
key = url;
}
if (mFilePathCache == null) {
return null;
} else {
return mFilePathCache.get(key);
}
}
/**
* 缓存bitmap到内存
*
* @param url
* @param bitmap
*/
public void cacheBitmap(String url, Bitmap bitmap) {
String key = url;
try {
key = CryptUtil.md5Hex(url);
} catch (Exception e) {
key = url;
}
checkAndCreateBitmapCache();
mBitmapLruCache.put(key, bitmap);
SaveImageDisk(bitmap, key);
}
/**
* 获取内存缓存的bitmap
*
* @param url
* @return
*/
public Bitmap getBitmap(String url) {
String key = url;
try {
key = CryptUtil.md5Hex(url);
} catch (Exception e) {
key = url;
}
if (mBitmapLruCache == null) {
return getBitmapFromDisk(key + ".jpg");
} else {
return mBitmapLruCache.get(key);
}
}
/**
* 检查和创建内存缓存
*/
public void checkAndCreateBitmapCache() {
if (mBitmapLruCache == null) {
long mTotalSize = Runtime.getRuntime().totalMemory();
mBitmapLruCache = new LruCache<>((int)(mTotalSize / 5));
final File dir = new File(context.getCacheDir(), CACHE_COVER_DIR);
if (dir.exists()) {
File[] listFiles = dir.listFiles();
if (null != listFiles && listFiles.length > 0) {
for (File file : listFiles) {
String fileName = file.getName();
fileName = fileName.substring(0, fileName.lastIndexOf("."));
String key = fileName;
mBitmapLruCache.put(key, getBitmapFromDisk(file.getAbsolutePath()));
}
}
}
}
}
/**
* 缓存图片到硬盘
* @param image
* @param url
*/
public void SaveImageDisk(Bitmap image, String url) {
final File dir = new File(context.getCacheDir(), CACHE_COVER_DIR);
if (!dir.exists()) {
dir.mkdirs();
}
String key = url;
try {
key = CryptUtil.md5Hex(key);
} catch (Exception e) {
key = url;
}
File imageDir = new File(dir, key + ".jpg");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(imageDir);
image.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
Log.e("CacheManage", "SaveImage:e" + e.getMessage());
} catch (IOException e) {
Log.e("CacheManage", "SaveImage:e" + e.getMessage());
}
}
/**
* 从硬盘读取文件
* @param path
* @return
*/
public Bitmap getBitmapFromDisk(String path) {
Bitmap bitmap = null;
FileInputStream fis = null;
File f = new File(path);
if (!f.exists()) {
return null;
}
try {
fis = new FileInputStream(path);
bitmap = BitmapFactory.decodeStream(fis);
} catch (FileNotFoundException e) {
Log.e("CacheManage", "getBitmap:e" + e.getMessage());
}
return bitmap;
}
}

View File

@ -0,0 +1,55 @@
package com.sean.rao.ali_auth.common;
public class Constant {
public static final String[] TYPES = {
"全屏(竖屏)", "全屏(横屏)", "弹窗(竖屏)",
"弹窗(横屏)", "底部弹窗", "自定义View", "自定义ViewXml","自定义Gif背景","自定义视频背景(mov,mp4)","自定义图片背景"
};
/**
* 全屏竖屏
*/
public static final int FULL_PORT = 0;
/**
* 全屏横屏
*/
public static final int FULL_LAND = 1;
/**
* 弹窗竖屏
*/
public static final int DIALOG_PORT = 2;
/**
* "弹窗(横屏)
*/
public static final int DIALOG_LAND = 3;
/**
* 底部弹窗
*/
public static final int DIALOG_BOTTOM = 4;
/**
* 自定义View
*/
public static final int CUSTOM_VIEW = 5;
/**
* 自定义ViewXml
*/
public static final int CUSTOM_XML = 6;
/**
* 自定义背景GIF
*/
public static final int CUSTOM_GIF = 7;
/**
* 自定义背景视频
*/
public static final int CUSTOM_MOV = 8;
/**
* 自定义背景图片
*/
public static final int CUSTOM_PIC = 9;
public static final String THEME_KEY = "theme";
public static final String LOGIN_TYPE = "login_type";
public static final int LOGIN = 1;
public static final int LOGIN_DELAY = 2;
}

View File

@ -0,0 +1,73 @@
package com.sean.rao.ali_auth.common;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import com.alibaba.fastjson2.JSONException;
import com.alibaba.fastjson2.JSONObject;
import com.mobile.auth.gatewayauth.AuthUIConfig;
import com.mobile.auth.gatewayauth.AuthUIControlClickListener;
import com.mobile.auth.gatewayauth.PhoneNumberAuthHelper;
import com.mobile.auth.gatewayauth.ResultCode;
import com.sean.rao.ali_auth.utils.StatusAll;
import com.sean.rao.ali_auth.utils.UtilTool;
import io.flutter.plugin.common.EventChannel;
/**
* @ProjectName: android
* @Package: com.sean.rao.ali_auth.common
* @ClassName: CUstomAuthUIControlClickListener
* @Description: java类作用描述
* @Author: liys
* @CreateDate: 5/12/22 5:26 PM
* @UpdateUser: 更新者
* @UpdateDate: 5/12/22 5:26 PM
* @UpdateRemark: 更新说明
* @Version: 1.0
*/
public class CustomAuthUIControlClickListener extends LoginParams implements AuthUIControlClickListener {
private final String TAG = "CustomAuth: ";
public CustomAuthUIControlClickListener() {
}
@Override
public void onClick(String code, Context context, String jsonString) {
JSONObject jsonDataObj = new JSONObject();
if(!TextUtils.isEmpty(jsonString)) {
jsonDataObj = JSONObject.parseObject(jsonString);
}
switch (code) {
//点击授权页默认样式的返回按钮
case ResultCode.CODE_ERROR_USER_CANCEL:
Log.e(TAG, "点击了授权页默认返回按钮");
break;
//点击授权页默认样式的切换其他登录方式 会关闭授权页
//如果不希望关闭授权页那就setSwitchAccHidden(true)隐藏默认的 通过自定义view添加自己的
case ResultCode.CODE_ERROR_USER_SWITCH:
Log.e(TAG, "点击了授权页默认切换其他登录方式");
break;
//点击一键登录按钮会发出此回调
//当协议栏没有勾选时 点击按钮会有默认toast 如果不需要或者希望自定义内容 setLogBtnToastHidden(true)隐藏默认Toast
//通过此回调自己设置toast
case ResultCode.CODE_ERROR_USER_LOGIN_BTN:
break;
//checkbox状态改变触发此回调
case ResultCode.CODE_ERROR_USER_CHECKBOX:
isChecked = jsonDataObj.getBooleanValue("isChecked");
Log.e(TAG, "checkbox状态变为" + jsonDataObj.getBooleanValue("isChecked"));
jsonDataObj = null;
break;
//点击协议栏触发此回调
case ResultCode.CODE_ERROR_USER_PROTOCOL_CONTROL:
Log.e(TAG, "点击协议," + "name: " + jsonDataObj.getString("name") + ", url: " + jsonDataObj.getString("url"));
break;
default:
break;
}
showResult(code, null, jsonDataObj);
}
}

View File

@ -0,0 +1,73 @@
package com.sean.rao.ali_auth.common;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class CustomRoundedDrawable extends Drawable {
private final Bitmap mBitmap;
private final Paint mPaint;
private final RectF mRectF;
private final float mRadius;
public CustomRoundedDrawable(Bitmap bitmap, float radius) {
mBitmap = bitmap;
mRadius = radius;
BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setShader(shader);
mRectF = new RectF();
}
@Override
public void draw(@NonNull Canvas canvas) {
mRectF.set(getBounds());
// 只对左上角和右上角设置圆角
float[] radii = {mRadius, 0, 0, mRadius, 0f, 0f, 0f, 0f};
// canvas.drawRoundRect(mRectF, mRadius, mRadius, mPaint);
// canvas.drawRoundRect(mRectF, radii, mPaint);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
// paint.setColor(0xFF0000FF);
Path path = new Path();
path.addRoundRect(mRectF, radii, Path.Direction.CW);
canvas.drawPath(path, paint); // 绘制具有四个不同圆角的矩形
}
@Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
mPaint.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return mPaint.getAlpha();
}
@Override
public int getIntrinsicWidth() {
return mBitmap.getWidth();
}
@Override
public int getIntrinsicHeight() {
return mBitmap.getHeight();
}
}

View File

@ -0,0 +1,75 @@
package com.sean.rao.ali_auth.common;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import androidx.annotation.RequiresApi;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import static android.os.FileUtils.copy;
/**
* @ProjectName: android
* @Package: com.sean.rao.ali_auth.common
* @ClassName: DownloadFile
* @Description: java类作用描述
* @Author: liys
* @CreateDate: 5/1/22 11:01 AM
* @UpdateUser: 更新者
* @UpdateDate: 5/1/22 11:01 AM
* @UpdateRemark: 更新说明
* @Version: 1.0
*/
class DownloadFile {
public static InputStream getImageToInputStream(String path) { //连接远程网址
InputStream inputStream = null;
try {
URL url = new URL(path);
HttpURLConnection conn=(HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
if (conn.getResponseCode() == 200) {
inputStream = conn.getInputStream();
}
} catch (IOException e) {
e.fillInStackTrace();
}
return inputStream;
}
public static Bitmap getImageToBitmap(String path) { //连接远程网址
Bitmap bitmap = null;
try {
URL url = new URL(path);
HttpURLConnection conn=(HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
if (conn.getResponseCode() == 200) {
InputStream inputStream = conn.getInputStream();
final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
OutputStream outputStream = new BufferedOutputStream(dataStream, 4 * 1024);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
copy(inputStream,outputStream);
}
outputStream.flush();
final byte[] data =dataStream.toByteArray();
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
}
} catch (IOException e) {
e.fillInStackTrace();
}
return bitmap;
}
}

View File

@ -0,0 +1,62 @@
package com.sean.rao.ali_auth.common;
import android.app.Activity;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import com.alibaba.fastjson2.JSONObject;
import com.mobile.auth.gatewayauth.AuthUIConfig;
import com.mobile.auth.gatewayauth.PhoneNumberAuthHelper;
import com.mobile.auth.gatewayauth.TokenResultListener;
import com.sean.rao.ali_auth.config.BaseUIConfig;
import com.sean.rao.ali_auth.utils.StatusAll;
import com.sean.rao.ali_auth.utils.UtilTool;
import org.jetbrains.annotations.Nullable;
import io.flutter.plugin.common.EventChannel;
public class LoginParams {
public static Activity mActivity;
public static Context mContext;
public static BaseUIConfig mUIConfig;
public static JSONObject jsonObject;
public static AuthUIConfig.Builder config;
public static boolean sdkAvailable = true;
public static EventChannel.EventSink eventSink;
public static TokenResultListener mTokenResultListener;
public static Boolean isChecked;
public static PhoneNumberAuthHelper mAuthHelper;
public void showResult(String code, String message, Object data){
if (eventSink != null) {
JSONObject result = resultFormatData(code, message, data);
result.put("isChecked", isChecked);
eventSink.success(result);
}
}
/**
* 返回数据封装
* @param code
* @param msg
* @param jsonDataObj
* @return
*/
public static JSONObject resultFormatData(String code, @Nullable String msg, @Nullable Object jsonDataObj){
JSONObject jsonObj = new JSONObject();
jsonObj.put("code", code);
jsonObj.put("msg", msg != null && !msg.isEmpty() ? msg : StatusAll.getName(code));
jsonObj.put("data", jsonDataObj != null ? jsonDataObj : "");
jsonObj.put("isChecked", jsonObject.getBooleanValue("privacyState", false));
return jsonObj;
}
}

View File

@ -0,0 +1,207 @@
package com.sean.rao.ali_auth.common;
/**
* @ProjectName: android
* @Package: com.sean.rao.ali_auth.common
* @ClassName: MediaFileUtil
* @Description: java类作用描述
* @Author: liys
* @CreateDate: 5/1/22 10:33 AM
* @UpdateUser: 更新者
* @UpdateDate: 5/1/22 10:33 AM
* @UpdateRemark: 更新说明
* @Version: 1.0
*/
import java.util.HashMap;
import java.util.Iterator;
/**
* 判断文件的类型 视频 音频 图片
*/
public class MediaFileUtil {
public static String sFileExtensions;
// Audio
public static final int FILE_TYPE_MP3 = 1;
public static final int FILE_TYPE_M4A = 2;
public static final int FILE_TYPE_WAV = 3;
public static final int FILE_TYPE_AMR = 4;
public static final int FILE_TYPE_AWB = 5;
public static final int FILE_TYPE_WMA = 6;
public static final int FILE_TYPE_OGG = 7;
private static final int FIRST_AUDIO_FILE_TYPE = FILE_TYPE_MP3;
private static final int LAST_AUDIO_FILE_TYPE = FILE_TYPE_OGG;
// MIDI
public static final int FILE_TYPE_MID = 11;
public static final int FILE_TYPE_SMF = 12;
public static final int FILE_TYPE_IMY = 13;
private static final int FIRST_MIDI_FILE_TYPE = FILE_TYPE_MID;
private static final int LAST_MIDI_FILE_TYPE = FILE_TYPE_IMY;
// Video
public static final int FILE_TYPE_MP4 = 21;
public static final int FILE_TYPE_M4V = 22;
public static final int FILE_TYPE_3GPP = 23;
public static final int FILE_TYPE_3GPP2 = 24;
public static final int FILE_TYPE_WMV = 25;
private static final int FIRST_VIDEO_FILE_TYPE = FILE_TYPE_MP4;
private static final int LAST_VIDEO_FILE_TYPE = FILE_TYPE_WMV;
// Image
public static final int FILE_TYPE_JPEG = 31;
public static final int FILE_TYPE_GIF = 32;
public static final int FILE_TYPE_PNG = 33;
public static final int FILE_TYPE_BMP = 34;
public static final int FILE_TYPE_WBMP = 35;
private static final int FIRST_IMAGE_FILE_TYPE = FILE_TYPE_JPEG;
private static final int LAST_IMAGE_FILE_TYPE = FILE_TYPE_WBMP;
// Playlist
public static final int FILE_TYPE_M3U = 41;
public static final int FILE_TYPE_PLS = 42;
public static final int FILE_TYPE_WPL = 43;
private static final int FIRST_PLAYLIST_FILE_TYPE = FILE_TYPE_M3U;
private static final int LAST_PLAYLIST_FILE_TYPE = FILE_TYPE_WPL;
//静态内部类
public static class MediaFileType {
int fileType;
String mimeType;
MediaFileType(int fileType, String mimeType) {
this.fileType = fileType;
this.mimeType = mimeType;
}
}
private static HashMap<String, MediaFileType> sFileTypeMap
= new HashMap<String, MediaFileType>();
private static HashMap<String, Integer> sMimeTypeMap
= new HashMap<String, Integer>();
static void addFileType(String extension, int fileType, String mimeType) {
sFileTypeMap.put(extension, new MediaFileType(fileType, mimeType));
sMimeTypeMap.put(mimeType, new Integer(fileType));
}
static {
addFileType("MP3", FILE_TYPE_MP3, "audio/mpeg");
addFileType("M4A", FILE_TYPE_M4A, "audio/mp4");
addFileType("WAV", FILE_TYPE_WAV, "audio/x-wav");
addFileType("AMR", FILE_TYPE_AMR, "audio/amr");
addFileType("AWB", FILE_TYPE_AWB, "audio/amr-wb");
addFileType("WMA", FILE_TYPE_WMA, "audio/x-ms-wma");
addFileType("OGG", FILE_TYPE_OGG, "application/ogg");
addFileType("MID", FILE_TYPE_MID, "audio/midi");
addFileType("XMF", FILE_TYPE_MID, "audio/midi");
addFileType("RTTTL", FILE_TYPE_MID, "audio/midi");
addFileType("SMF", FILE_TYPE_SMF, "audio/sp-midi");
addFileType("IMY", FILE_TYPE_IMY, "audio/imelody");
addFileType("MP4", FILE_TYPE_MP4, "video/mp4");
addFileType("M4V", FILE_TYPE_M4V, "video/mp4");
addFileType("3GP", FILE_TYPE_3GPP, "video/3gpp");
addFileType("3GPP", FILE_TYPE_3GPP, "video/3gpp");
addFileType("3G2", FILE_TYPE_3GPP2, "video/3gpp2");
addFileType("3GPP2", FILE_TYPE_3GPP2, "video/3gpp2");
addFileType("WMV", FILE_TYPE_WMV, "video/x-ms-wmv");
addFileType("JPG", FILE_TYPE_JPEG, "image/jpeg");
addFileType("JPEG", FILE_TYPE_JPEG, "image/jpeg");
addFileType("GIF", FILE_TYPE_GIF, "image/gif");
addFileType("PNG", FILE_TYPE_PNG, "image/png");
addFileType("BMP", FILE_TYPE_BMP, "image/x-ms-bmp");
addFileType("WBMP", FILE_TYPE_WBMP, "image/vnd.wap.wbmp");
addFileType("M3U", FILE_TYPE_M3U, "audio/x-mpegurl");
addFileType("PLS", FILE_TYPE_PLS, "audio/x-scpls");
addFileType("WPL", FILE_TYPE_WPL, "application/vnd.ms-wpl");
// compute file extensions list for native Media Scanner
StringBuilder builder = new StringBuilder();
Iterator<String> iterator = sFileTypeMap.keySet().iterator();
while (iterator.hasNext()) {
if (builder.length() > 0) {
builder.append(',');
}
builder.append(iterator.next());
}
sFileExtensions = builder.toString();
}
public static final String UNKNOWN_STRING = "<unknown>";
public static boolean isAudioFileType(int fileType) {
return ((fileType >= FIRST_AUDIO_FILE_TYPE &&
fileType <= LAST_AUDIO_FILE_TYPE) ||
(fileType >= FIRST_MIDI_FILE_TYPE &&
fileType <= LAST_MIDI_FILE_TYPE));
}
public static boolean isVideoFileType(int fileType) {
return (fileType >= FIRST_VIDEO_FILE_TYPE &&
fileType <= LAST_VIDEO_FILE_TYPE);
}
public static boolean isImageFileType(int fileType) {
return (fileType >= FIRST_IMAGE_FILE_TYPE &&
fileType <= LAST_IMAGE_FILE_TYPE);
}
public static boolean isPlayListFileType(int fileType) {
return (fileType >= FIRST_PLAYLIST_FILE_TYPE &&
fileType <= LAST_PLAYLIST_FILE_TYPE);
}
public static MediaFileType getFileType(String path) {
int lastDot = path.lastIndexOf(".");
if (lastDot < 0)
return null;
return sFileTypeMap.get(path.substring(lastDot + 1).toUpperCase());
}
//根据视频文件路径判断文件类型
public static boolean isVideoFileType(String path) {
MediaFileType type = getFileType(path);
if(null != type) {
return isVideoFileType(type.fileType);
}
return false;
}
//根据音频文件路径判断文件类型
public static boolean isAudioFileType(String path) {
MediaFileType type = getFileType(path);
if(null != type) {
return isAudioFileType(type.fileType);
}
return false;
}
//根据mime类型查看文件类型
public static int getFileTypeForMimeType(String mimeType) {
Integer value = sMimeTypeMap.get(mimeType);
return (value == null ? 0 : value.intValue());
}
//根据图片文件路径判断是否时gif文件类型
public static boolean isImageGifFileType(String path) {
MediaFileType type = getFileType(path);
if(null != type) {
return FILE_TYPE_GIF == type.fileType;
}
return false;
}
//根据图片文件路径判断文件类型
public static boolean isImageFileType(String path) {
MediaFileType type = getFileType(path);
if(null != type) {
return isImageFileType(type.fileType);
}
return false;
}
}

View File

@ -0,0 +1,584 @@
package com.sean.rao.ali_auth.common;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Application;
import android.app.Application.ActivityLifecycleCallbacks;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Movie;
import android.graphics.SurfaceTexture;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.media.MediaMetadataRetriever;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnInfoListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaPlayer.OnVideoSizeChangedListener;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.Surface;
import android.view.TextureView;
import android.view.TextureView.SurfaceTextureListener;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.FrameLayout.LayoutParams;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import androidx.annotation.NonNull;
import com.alibaba.fastjson2.JSONObject;
import com.mobile.auth.gatewayauth.LoginAuthActivity;
import com.mobile.auth.gatewayauth.PhoneNumberAuthHelper;
import com.mobile.auth.gatewayauth.model.TokenRet;
import com.sean.rao.ali_auth.common.CacheManage;
import com.sean.rao.ali_auth.common.GifAnimationDrawable;
import com.sean.rao.ali_auth.utils.AppUtils;
import com.sean.rao.ali_auth.utils.UtilTool;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.util.concurrent.ExecutorService;
import io.flutter.plugin.common.EventChannel;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
/**
* @Package: com.aliqin.mytel
* @ClassName: NativeBackgroundAdapter
* @Description: 类作用描述
* @Author: liuqi
* @CreateDate: 2021/4/29 4:53 PM
* @Version: 1.0
*/
public class NativeBackgroundAdapter extends LoginParams{
private volatile OnGifListener onGifListener;
private volatile GifAnimationDrawable gifAnimationDrawable;
private CacheManage mCacheManage;
private ExecutorService mExecutorService;
private String key, path;
public NativeBackgroundAdapter(CacheManage cacheManage, ExecutorService executorService, String key) {
this.key = key;
this.path = jsonObject.getString("pageBackgroundPath");
mCacheManage = cacheManage;
mExecutorService = executorService;
mCacheManage.checkAndCreateBitmapCache();
if ("gifPath".equals(key)) {
if (null == mCacheManage.getBitmap(path)) {
getAssetGifFirstFrame(mContext, path);
}
}
if ("videoPath".equals(key)) {
if (null == mCacheManage.getBitmap(path)) {
mExecutorService.execute(new Runnable() {
@Override
public void run() {
Bitmap bitmap = getAssetVideoCoverBitmap(mContext.getAssets(), path);
if(null!=bitmap) {
mCacheManage.cacheBitmap(path, bitmap);
}
}
});
}
}
}
/**
* 加载布局
*
* @param frameLayout 容器
* @param backgroundColor 背景颜色
*/
public void solveView(final FrameLayout frameLayout, String backgroundColor) {
if ("imagePath".equals(key)) {
ImageView imageView = new ImageView(frameLayout.getContext());
LayoutParams params = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
imageView.setScaleType(ScaleType.CENTER_CROP);
imageView.setImageDrawable(toDrawable(path, frameLayout.getContext()));
frameLayout.addView(imageView, params);
if (!TextUtils.isEmpty(backgroundColor)) {
imageView.setBackgroundColor(Color.parseColor(backgroundColor));
}
} else if ("gifPath".equals(key)) {
final ImageView imageView = new ImageView(frameLayout.getContext());
LayoutParams params = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
imageView.setScaleType(ScaleType.CENTER_CROP);
if (!TextUtils.isEmpty(backgroundColor)) {
imageView.setBackgroundColor(Color.parseColor(backgroundColor));
}
frameLayout.addView(imageView, params);
if (gifAnimationDrawable != null) {
playGif(imageView, gifAnimationDrawable);
} else {
if (!TextUtils.isEmpty(backgroundColor)) {
imageView.setBackgroundColor(Color.parseColor(backgroundColor));
}
onGifListener = new OnGifListener() {
@Override
public void onGifDownloaded(final GifAnimationDrawable drawable) {
if (drawable != null && null != imageView) {
imageView.post(new Runnable() {
@Override
public void run() {
gifAnimationDrawable = drawable;
playGif(imageView, drawable);
}
});
}
}
@Override
public void onFirstFrame(final Bitmap bitmap) {
imageView.post(new Runnable() {
@Override
public void run() {
if (null == gifAnimationDrawable) {
imageView.setImageBitmap(bitmap);
}
}
});
}
};
if (null != mCacheManage.getBitmap(path)) {
imageView.setImageBitmap(mCacheManage.getBitmap(path));
}
readGifAsset(frameLayout.getContext(), path);
}
} else if ("videoPath".equals(key)) {
playVideo(frameLayout, path, backgroundColor);
}
// 构建关闭按钮
createImageButton(frameLayout, path);
}
/**
* 获取asset文件夹视频封面
*
* @param assetManager
* @param videoPath
* @return
*/
public static Bitmap getAssetVideoCoverBitmap(AssetManager assetManager, String videoPath) {
Bitmap bitmap = null;
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try {
AssetFileDescriptor afd = assetManager.openFd(videoPath);
retriever.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
//获得第一帧图片
bitmap = retriever.getFrameAtTime();
try {
retriever.release();
} catch (RuntimeException ex) {
ex.printStackTrace();
}
} catch (IllegalArgumentException | IOException ex) {
ex.printStackTrace();
Log.e("NativeBackgroundAdapter", "getAssetVideoBitmap:" + ex.getMessage());
}
return bitmap;
}
/**
* 获取本地gif第一帧
*
* @param path
*/
public void getAssetGifFirstFrame(final Context context, final String path) {
mExecutorService.execute(new Runnable() {
@Override
public void run() {
try {
InputStream inputStream = context.getAssets().open(path);
// InputStream inputStream = DownloadFile.getImageToInputStream(path);
Movie gif = Movie.decodeStream(inputStream);
final Bitmap firstFrame = Bitmap.createBitmap(gif.width(), gif.height(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(firstFrame);
gif.draw(canvas, 0, 0);
canvas.save();
mCacheManage.cacheBitmap(path, firstFrame);
OnGifListener gifListener = onGifListener;
if (gifListener != null) {
gifListener.onFirstFrame(firstFrame);
}
inputStream.close();
} catch (IOException e) {
Log.e("NativeBackgroundAdapter", "getGifFirstFrame:" + e.getMessage());
}
}
});
}
/**
* 播放视频
*
* @param frameLayout
* @param path url或者路径
* @param backgroundColor
*/
@TargetApi(VERSION_CODES.JELLY_BEAN)
private void playVideo(final FrameLayout frameLayout, final String path, String backgroundColor) {
final MediaPlayer[] mediaPlayer = {new MediaPlayer()};
final TextureView textureView = new TextureView(frameLayout.getContext());
LayoutParams params = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
frameLayout.addView(textureView, params);
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
textureView.setBackground(null);
}
final ImageView ivCover = new ImageView(frameLayout.getContext());
LayoutParams paramsIv = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
ivCover.setScaleType(ScaleType.CENTER_CROP);
if (null != mCacheManage.getBitmap(path)) {
ivCover.setImageBitmap(mCacheManage.getBitmap(path));
} else {
if (!TextUtils.isEmpty(backgroundColor)) {
frameLayout.setBackgroundColor(Color.parseColor(backgroundColor));
}
}
frameLayout.addView(ivCover, paramsIv);
final ActivityLifecycleCallbacks activityLifecycleCallbacks = new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
if (activity instanceof LoginAuthActivity) {
if (mediaPlayer[0] != null && !mediaPlayer[0].isPlaying()) {
mediaPlayer[0].start();
}
}
}
@Override
public void onActivityPaused(Activity activity) {
if (activity instanceof LoginAuthActivity) {
if (mediaPlayer[0] != null && mediaPlayer[0].isPlaying()) {
mediaPlayer[0].pause();
}
}
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
if (activity instanceof LoginAuthActivity) {
if (mediaPlayer[0] != null && mediaPlayer[0].isPlaying()) {
mediaPlayer[0].stop();
mediaPlayer[0].release();
mediaPlayer[0] = null;
}
activity.getApplication().unregisterActivityLifecycleCallbacks(this);
}
}
};
((Application)frameLayout.getContext()).registerActivityLifecycleCallbacks(
activityLifecycleCallbacks);
mediaPlayer[0].setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer[0].setLooping(true);
mediaPlayer[0].setVolume(0, 0);
AssetFileDescriptor afd;
try {
afd = frameLayout.getContext().getAssets().openFd(path);
mediaPlayer[0].setDataSource(afd.getFileDescriptor(), afd.getStartOffset(),
afd.getLength());
} catch (Exception e) {
Log.e("NativeBackgroundAdapter", "playVideo===readAssets:" + e.getMessage());
}
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
mediaPlayer[0].setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
}
try {
mediaPlayer[0].setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mediaPlayer[0].setOnInfoListener(new OnInfoListener() {
@Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END) {
return true;
} else if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
ivCover.setVisibility(View.GONE);
}
return false;
}
});
mediaPlayer[0].start();
}
});
mediaPlayer[0].setOnVideoSizeChangedListener(new OnVideoSizeChangedListener() {
@Override
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
int mVideoHeight = mediaPlayer[0].getVideoHeight();
int mVideoWidth = mediaPlayer[0].getVideoWidth();
updateTextureViewSizeCenter(textureView, mVideoWidth, mVideoHeight);
}
});
mediaPlayer[0].prepareAsync();
textureView.setSurfaceTextureListener(new SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width,
int height) {
Surface mSurface = new Surface(surface);
mediaPlayer[0].setSurface(mSurface);
}
@Override
public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width,
int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
if (mediaPlayer[0] != null && mediaPlayer[0].isPlaying()) {
mediaPlayer[0].pause();
}
return false;
}
@Override
public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
}
});
} catch (Exception ignored) {
}
}
/**
* 设置视频适应模式为center_crop
*
* @param textureView
* @param mVideoWidth
* @param mVideoHeight
*/
private void updateTextureViewSizeCenter(TextureView textureView, int mVideoWidth, int mVideoHeight) {
float sx = (float)textureView.getWidth() / (float)mVideoWidth;
float sy = (float)textureView.getHeight() / (float)mVideoHeight;
Matrix matrix = new Matrix();
float maxScale = Math.max(sx, sy);
//第1步:把视频区移动到View区,使两者中心点重合.
matrix.preTranslate((textureView.getWidth() - mVideoWidth) / 2, (textureView.getHeight() - mVideoHeight) / 2);
//第2步:因为默认视频是fitXY的形式显示的,所以首先要缩放还原回来.
matrix.preScale(mVideoWidth / (float)textureView.getWidth(), mVideoHeight / (float)textureView.getHeight());
//第3步,等比例放大或缩小,直到视频区的一边超过View一边, 另一边与View的另一边相等. 因为超过的部分超出了View的范围,所以是不会显示的,相当于裁剪了.
matrix.postScale(maxScale, maxScale, textureView.getWidth() / 2,
textureView.getHeight() / 2);//后两个参数坐标是以整个View的坐标系以参考的
textureView.setTransform(matrix);
textureView.postInvalidate();
}
/**
* 从本地读取gif
*
* @param path
*/
private void readGifAsset(final Context context, final String path) {
mExecutorService.execute(new Runnable() {
@Override
public void run() {
AssetManager assetManager = context.getAssets();
try {
InputStream inputStream = assetManager.open(
path);
final GifAnimationDrawable gifAnimationDrawable = new GifAnimationDrawable(inputStream);
if (onGifListener != null) {
onGifListener.onGifDownloaded(gifAnimationDrawable);
}
} catch (IOException e) {
Log.e("NativeBackgroundAdapter", "read gif asset:" + e.getMessage());
}
}
});
}
/**
* 播放gif动画
*
* @param imageView
* @param gifAnimationDrawable
*/
private void playGif(final ImageView imageView, final GifAnimationDrawable gifAnimationDrawable) {
Log.e("NativeBackgroundAdapter", "playGif asset");
final ActivityLifecycleCallbacks activityLifecycleCallbacks = new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
if (activity instanceof LoginAuthActivity) {
if (gifAnimationDrawable != null && !gifAnimationDrawable.isRunning()) {
imageView.postDelayed(new Runnable() {
@Override
public void run() {
gifAnimationDrawable.start();
}
}, 50);
}
}
}
@Override
public void onActivityPaused(Activity activity) {
if (activity instanceof LoginAuthActivity) {
if (gifAnimationDrawable != null && gifAnimationDrawable.isRunning()) {
gifAnimationDrawable.stop();
}
}
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
if (activity instanceof LoginAuthActivity) {
activity.getApplication().unregisterActivityLifecycleCallbacks(this);
}
}
};
((Application)imageView.getContext()).registerActivityLifecycleCallbacks(
activityLifecycleCallbacks);
imageView.setImageDrawable(gifAnimationDrawable);
gifAnimationDrawable.start();
}
public interface OnGifListener {
/**
* gif下载完成监听
*
* @param drawable
*/
void onGifDownloaded(GifAnimationDrawable drawable);
/**
* 获取第一帧完成监听
*
* @param bitmap
*/
void onFirstFrame(Bitmap bitmap);
}
/**
* 创建图片按钮
* @param frameLayout
* @param path
* @return
*/
protected void createImageButton(final FrameLayout frameLayout, final String path){
JSONObject customRetureBtn = jsonObject.getJSONObject("customReturnBtn");
if (customRetureBtn != null) {
try{
LinearLayout linearLayout = new LinearLayout(frameLayout.getContext());
/// 是否留出状态栏的高度
// linearLayout.setFitsSystemWindows(false);
LayoutParams linearLayoutParams = new LayoutParams(MATCH_PARENT, WRAP_CONTENT);
ImageButton imageButton = new ImageButton(frameLayout.getContext());
imageButton.setPadding(0, 0, 0, 0);
imageButton.setBackgroundColor(Color.TRANSPARENT);
imageButton.setScaleType(ScaleType.values()[customRetureBtn.getIntValue("imgScaleType")]);
imageButton.setImageDrawable(UtilTool.getBitmapToBitmapDrawable(frameLayout.getContext(), UtilTool.flutterToPath(customRetureBtn.getString("imgPath"))));
LayoutParams buttonParams = new LayoutParams(
AppUtils.dp2px(frameLayout.getContext(), customRetureBtn.getIntValue("width")),
AppUtils.dp2px(frameLayout.getContext(), customRetureBtn.getIntValue("height"))
);
buttonParams.setMargins(
AppUtils.dp2px(frameLayout.getContext(), customRetureBtn.getIntValue("left")),
AppUtils.dp2px(frameLayout.getContext(), customRetureBtn.getIntValue("top")),
AppUtils.dp2px(frameLayout.getContext(), customRetureBtn.getIntValue("right")),
AppUtils.dp2px(frameLayout.getContext(), customRetureBtn.getIntValue("bottom"))
);
imageButton.setOnClickListener(v -> {
eventSink.success(UtilTool.resultFormatData("700000", null, null));
mAuthHelper.quitLoginPage();
});
linearLayout.addView(imageButton, buttonParams);
frameLayout.addView(linearLayout, linearLayoutParams);
} catch (IOException e) {
eventSink.success(UtilTool.resultFormatData("500000", null, e.getMessage()));
}
}
}
protected static Drawable toDrawable(String imgUrl, Context context) {
Drawable drawable = null;
Bitmap bitmap = null;
InputStream inputStream = null;
try {
AssetManager assetManager = context.getAssets();
inputStream = assetManager.open(imgUrl);
bitmap = BitmapFactory.decodeStream(inputStream);
drawable = new BitmapDrawable(context.getResources(), bitmap);
} catch (Exception var6) {
var6.printStackTrace();
if (bitmap != null) {
bitmap.recycle();
}
Log.e("AuthSDK", "e=" + var6.toString());
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return drawable;
}
}

View File

@ -0,0 +1,17 @@
package com.sean.rao.ali_auth.common;
/**
* @ProjectName: android
* @Package: com.sean.rao.ali_auth.common
* @ClassName: OnListener
* @Description: java类作用描述
* @Author: liys
* @CreateDate: 6/13/22 4:21 PM
* @UpdateUser: 更新者
* @UpdateDate: 6/13/22 4:21 PM
* @UpdateRemark: 更新说明
* @Version: 1.0
*/
public interface OnListener {
void CallBack(boolean status);
}

View File

@ -0,0 +1,223 @@
package com.sean.rao.ali_auth.config;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.Space;
import android.widget.TextView;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.sean.rao.ali_auth.common.Constant;
import com.sean.rao.ali_auth.common.LoginParams;
import com.sean.rao.ali_auth.utils.AppUtils;
import com.sean.rao.ali_auth.utils.UtilTool;
import java.io.IOException;
import io.flutter.plugin.common.EventChannel;
public abstract class BaseUIConfig extends LoginParams {
public int mScreenWidthDp;
public int mScreenHeightDp;
public static BaseUIConfig init(int type) {
isChecked = false;
switch (type) {
case Constant.FULL_PORT:
return new FullPortConfig();
case Constant.FULL_LAND:
return new FullLandConfig();
case Constant.DIALOG_PORT:
return new DialogPortConfig();
case Constant.DIALOG_LAND:
return new DialogLandConfig();
case Constant.DIALOG_BOTTOM:
return new DialogBottomConfig();
case Constant.CUSTOM_XML:
return new CustomXmlConfig();
default:
if (jsonObject.getString("pageBackgroundPath") != null && !jsonObject.getString("pageBackgroundPath").isEmpty()) {
if (jsonObject.getString("pageBackgroundPath").equals("xml")) {
return new CustomXmlConfig();
} else if (jsonObject.getString("pageBackgroundPath").equals("view")) {
return new CustomViewConfig();
} else {
return new CustomAssetsConfig();
}
}
return null;
}
}
/**
* 删除自定义布局参数防止内存溢出
*/
public BaseUIConfig() {
// 防止内存泄漏
mAuthHelper.removeAuthRegisterXmlConfig();
mAuthHelper.removeAuthRegisterViewConfig();
}
/**
* 第三方布局设置
* @param marginTop
* @return
*/
protected View initSwitchView(int marginTop) {
JSONObject customThirdView = jsonObject.getJSONObject("customThirdView");
/// 名称列表
JSONArray customThirdViewName = customThirdView.getJSONArray("viewItemName");
/// 图片路径列表
JSONArray customThirdViewItem = customThirdView.getJSONArray("viewItemPath");
if (customThirdViewName != null && customThirdViewItem != null) {
LinearLayout linearLayout = new LinearLayout(mContext);
// 创建一个最大宽度和适量高度的布局
LinearLayout.LayoutParams LayoutParams = new LinearLayout.LayoutParams(
customThirdView.getFloatValue("width") > 0 ? AppUtils.dp2px(mContext, customThirdView.getFloatValue("width")) : LinearLayout.LayoutParams.MATCH_PARENT,
customThirdView.getFloatValue("height") > 0 ? AppUtils.dp2px(mContext, customThirdView.getFloatValue("height")) : LinearLayout.LayoutParams.WRAP_CONTENT
);
// 居中边距
LayoutParams.setMargins(
AppUtils.dp2px(mContext, customThirdView.getFloatValue("left") > 0 ? customThirdView.getFloatValue("left") : 10),
AppUtils.dp2px(mContext, customThirdView.getFloatValue("top") > 0 ? customThirdView.getFloatValue("top") : marginTop),
AppUtils.dp2px(mContext, customThirdView.getFloatValue("right") > 0 ? customThirdView.getFloatValue("right") : 10),
AppUtils.dp2px(mContext, customThirdView.getFloatValue("bottom") > 0 ? customThirdView.getFloatValue("bottom") : 10)
);
linearLayout.setLayoutParams(LayoutParams);
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
linearLayout.setGravity(Gravity.CENTER_HORIZONTAL);
for (int i = 0; i < customThirdViewItem.size(); i++) {
if (customThirdViewItem.get(i) != null && !String.valueOf(customThirdViewItem.get(i)).isEmpty()) {
int finalI = i;
/// 每个item布局
LinearLayout itemLinearLayout = new LinearLayout(mContext);
/// 按钮和文字布局
itemLinearLayout.setOrientation(LinearLayout.VERTICAL);
/// 按钮控件
ImageButton itemButton = new ImageButton(mActivity);
/// 需要转化路径
try {
itemButton.setBackground(
UtilTool.getBitmapToBitmapDrawable(
mContext,
UtilTool.flutterToPath(String.valueOf(customThirdViewItem.get(i)))
)
);
} catch (IOException e) {
// eventSink.success(UtilTool.resultFormatData("500000", null, e.getMessage()));
showResult("500000", "出现错误", e.getMessage());
}
ViewGroup.LayoutParams buttonLayoutParams = new ViewGroup.LayoutParams(
AppUtils.dp2px(mContext, customThirdView.getFloatValue("itemWidth") > 0 ? customThirdView.getFloatValue("itemWidth") : 60),
AppUtils.dp2px(mContext, customThirdView.getFloatValue("itemHeight") > 0 ? customThirdView.getFloatValue("itemHeight") : 60)
);
itemButton.setLayoutParams(buttonLayoutParams);
/// 第三方按钮的点击事件
itemButton.setOnClickListener(v -> {
// 判断是否隐藏toast
showResult("700005", "点击第三方登录按钮", finalI);
// eventSink.success(UtilTool.resultFormatData("600019", null, finalI));
// if (!jsonObject.getBooleanValue("isHideToast") && !isChecked) {
// Toaster.show(jsonObject.getString("toastText"));
// return;
// }
if (jsonObject.getBooleanValue("autoQuitPage")) {
mAuthHelper.quitLoginPage();
}
});
itemLinearLayout.addView(itemButton);
Object itemName = customThirdViewName.get(i);
if (itemName != null && !String.valueOf(itemName).isEmpty()) {
// 按钮下文字控件
TextView textView = new TextView(mContext);
textView.setText(String.valueOf(itemName));
// 文字颜色
textView.setTextColor(customThirdView.getString("color") != null && !customThirdView.getString("color").isEmpty() ? Color.parseColor(customThirdView.getString("color")) : Color.BLACK);
textView.setTextSize(
TypedValue.COMPLEX_UNIT_SP,
customThirdView.getFloatValue("size") > 0 ? customThirdView.getFloatValue("size") : 14F
);
textView.setGravity(Gravity.CENTER);
itemLinearLayout.addView(textView);
}
/// 新增按钮间距控件
if (i > 0 && i < customThirdViewItem.size()) {
Space space = new Space(mContext);
space.setLayoutParams(new ViewGroup.LayoutParams(
AppUtils.dp2px(mContext, customThirdView.getFloatValue("space") > 0 ? customThirdView.getFloatValue("space") : 10),
LinearLayout.LayoutParams.MATCH_PARENT)
);
linearLayout.addView(space);
}
/// 将item放入布局中
linearLayout.addView(itemLinearLayout);
}
}
return linearLayout;
} else {
return null;
}
}
/**
* 更新屏幕
* @param authPageScreenOrientation
*/
protected void updateScreenSize(int authPageScreenOrientation) {
int screenHeightDp = AppUtils.px2dp(mContext, AppUtils.getPhoneHeightPixels(mContext));
int screenWidthDp = AppUtils.px2dp(mContext, AppUtils.getPhoneWidthPixels(mContext));
int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
if (authPageScreenOrientation == ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
authPageScreenOrientation = mActivity.getRequestedOrientation();
}
if (authPageScreenOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|| authPageScreenOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|| authPageScreenOrientation == ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE) {
rotation = Surface.ROTATION_90;
} else if (authPageScreenOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|| authPageScreenOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
|| authPageScreenOrientation == ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT) {
rotation = Surface.ROTATION_180;
}
switch (rotation) {
case Surface.ROTATION_0:
case Surface.ROTATION_180:
mScreenWidthDp = screenWidthDp;
mScreenHeightDp = screenHeightDp;
break;
case Surface.ROTATION_90:
case Surface.ROTATION_270:
mScreenWidthDp = screenHeightDp;
mScreenHeightDp = screenWidthDp;
break;
default:
break;
}
}
public abstract void configAuthPage();
private void configBuild(){}
/**
* 在横屏APP弹竖屏一键登录页面或者竖屏APP弹横屏授权页时处理特殊逻辑
* Android8.0只能启动SCREEN_ORIENTATION_BEHIND模式的Activity
*/
public void onResume() {}
}

View File

@ -0,0 +1,79 @@
package com.sean.rao.ali_auth.config;
import android.content.pm.ActivityInfo;
import android.os.Build;
import android.view.View;
import android.widget.FrameLayout;
import com.mobile.auth.gatewayauth.AuthRegisterViewConfig;
import com.mobile.auth.gatewayauth.AuthRegisterXmlConfig;
import com.mobile.auth.gatewayauth.ui.AbstractPnsViewDelegate;
import com.sean.rao.ali_auth.R;
import com.sean.rao.ali_auth.common.CacheManage;
import com.sean.rao.ali_auth.common.MediaFileUtil;
import com.sean.rao.ali_auth.common.NativeBackgroundAdapter;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* xml文件方便预览
* 可以通过addAuthRegisterXmlConfig一次性统一添加授权页的所有自定义view
*/
public class CustomAssetsConfig extends BaseUIConfig {
private CacheManage mCacheManage;
private ExecutorService mThreadExecutor;
private NativeBackgroundAdapter nativeBackgroundAdapter;
public CustomAssetsConfig() {
super();
String fileType = "imagePath";
if (jsonObject.getString("pageBackgroundPath") != null && !jsonObject.getString("pageBackgroundPath").isEmpty()) {
if (MediaFileUtil.isImageGifFileType(jsonObject.getString("pageBackgroundPath"))) {
fileType = "gifPath";
} else if (MediaFileUtil.isVideoFileType(jsonObject.getString("pageBackgroundPath"))) {
fileType = "videoPath";
}
}
mCacheManage=new CacheManage(mActivity.getApplication());
mThreadExecutor=new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),
Runtime.getRuntime().availableProcessors(),
0,
TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(10),
new ThreadPoolExecutor.CallerRunsPolicy()
);
nativeBackgroundAdapter = new NativeBackgroundAdapter(mCacheManage, mThreadExecutor, fileType);
}
@Override
public void configAuthPage() {
int authPageOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
if (Build.VERSION.SDK_INT == 26) {
authPageOrientation = ActivityInfo.SCREEN_ORIENTATION_BEHIND;
}
updateScreenSize(authPageOrientation);
//sdk默认控件的区域是marginTop50dp
int designHeight = mScreenHeightDp - 50;
int unit = designHeight / 10;
mAuthHelper.addAuthRegisterXmlConfig(new AuthRegisterXmlConfig.Builder()
.setLayout(R.layout.authsdk_widget_custom_layout, new AbstractPnsViewDelegate() {
@Override
public void onViewCreated(View view) {
final FrameLayout fly_container = view.findViewById(R.id.fly_container);
// final Button close = view.findViewById(R.id.close);
// fly_container.setOnApplyWindowInsetsListener();
nativeBackgroundAdapter.solveView(fly_container, "#3F51B5");
}
})
.build());
//添加自定义切换其他登录方式
mAuthHelper.addAuthRegistViewConfig("switch_msg", new AuthRegisterViewConfig.Builder()
.setView(initSwitchView(420))
.setRootViewId(AuthRegisterViewConfig.RootViewId.ROOT_VIEW_ID_BODY)
.build());
mAuthHelper.setAuthUIConfig(config.setScreenOrientation(authPageOrientation).create());
}
}

View File

@ -0,0 +1,86 @@
package com.sean.rao.ali_auth.config;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.os.Build;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.mobile.auth.gatewayauth.AuthRegisterViewConfig;
import com.mobile.auth.gatewayauth.CustomInterface;
import static com.nirvana.tools.core.AppUtils.dp2px;
/**
* 号码栏水平位置的自定义view 推荐使用addAuthRegistViewConfig 可以添加到相对精准的位置
*/
public class CustomViewConfig extends BaseUIConfig {
public CustomViewConfig() {
super();
}
@Override
public void configAuthPage() {
mAuthHelper.addAuthRegistViewConfig("switch_msg", new AuthRegisterViewConfig.Builder()
.setView(initSwitchView(350))
.setRootViewId(AuthRegisterViewConfig.RootViewId.ROOT_VIEW_ID_BODY)
.setCustomInterface(new CustomInterface() {
@Override
public void onClick(Context context) {
// Toast.makeText(mContext, "切换到短信登录方式", Toast.LENGTH_SHORT).show();
// Intent pIntent = new Intent(mActivity, MessageActivity.class);
// mActivity.startActivityForResult(pIntent, 1002);
// mAuthHelper.quitLoginPage();
}
}).build());
mAuthHelper.addAuthRegistViewConfig("number_logo", new AuthRegisterViewConfig.Builder()
.setView(initNumberLogoView())
.setRootViewId(AuthRegisterViewConfig.RootViewId.ROOT_VIEW_ID_NUMBER)
.setCustomInterface(new CustomInterface() {
@Override
public void onClick(Context context) {
}
}).build());
mAuthHelper.addAuthRegistViewConfig("back_btn", new AuthRegisterViewConfig.Builder()
.setView(initBackBtn())
.setRootViewId(AuthRegisterViewConfig.RootViewId.ROOT_VIEW_ID_TITLE_BAR)
.setCustomInterface(new CustomInterface() {
@Override
public void onClick(Context context) {
mAuthHelper.quitLoginPage();
mActivity.finish();
}
}).build());
int authPageOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
if (Build.VERSION.SDK_INT == 26) {
authPageOrientation = ActivityInfo.SCREEN_ORIENTATION_BEHIND;
}
mAuthHelper.setAuthUIConfig(config.setScreenOrientation(authPageOrientation).create());
}
private ImageView initNumberLogoView() {
ImageView pImageView = new ImageView(mContext);
// pImageView.setImageResource(R.drawable.phone);
pImageView.setScaleType(ImageView.ScaleType.FIT_XY);
RelativeLayout.LayoutParams pParams = new RelativeLayout.LayoutParams(dp2px(mContext, 30), dp2px(mContext, 30));
pParams.setMargins(dp2px(mContext, 100), 0, 0, 0);
pImageView.setLayoutParams(pParams);
return pImageView;
}
private ImageView initBackBtn() {
ImageView pImageView = new ImageView(mContext);
// pImageView.setImageResource(R.drawable.icon_close);
pImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
RelativeLayout.LayoutParams pParams = new RelativeLayout.LayoutParams(dp2px(mContext, 20), dp2px(mContext, 20));
pParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
pParams.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
pParams.setMargins(dp2px(mContext, 12.0F), 0, 0, 0);
pImageView.setLayoutParams(pParams);
return pImageView;
}
}

View File

@ -0,0 +1,63 @@
package com.sean.rao.ali_auth.config;
import android.content.pm.ActivityInfo;
import android.os.Build;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.RelativeLayout;
import com.mobile.auth.gatewayauth.AuthRegisterXmlConfig;
import com.mobile.auth.gatewayauth.ui.AbstractPnsViewDelegate;
import com.sean.rao.ali_auth.R;
/**
* xml文件方便预览
* 可以通过addAuthRegisterXmlConfig一次性统一添加授权页的所有自定义view
*/
public class CustomXmlConfig extends BaseUIConfig {
public CustomXmlConfig() {
super();
}
@Override
public void configAuthPage() {
int authPageOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
if (Build.VERSION.SDK_INT == 26) {
authPageOrientation = ActivityInfo.SCREEN_ORIENTATION_BEHIND;
}
int getCustomXml = mContext.getResources().getIdentifier("custom_full_port", "layout", mContext.getPackageName());
// 判断是否有自定义布局文件没有则加载默认布局文件
if(getCustomXml == 0){
getCustomXml = mContext.getResources().getIdentifier("custom_full_port", "layout", mContext.getPackageName());
}
View customXmlLayout = LayoutInflater.from(mContext).inflate(getCustomXml, new RelativeLayout(mContext), false);
mAuthHelper.addAuthRegisterXmlConfig(new AuthRegisterXmlConfig.Builder()
.setLayout(getCustomXml, new AbstractPnsViewDelegate() {
@Override
public void onViewCreated(View view) {
findViewById(R.id.btn_back).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/// 点击关闭按钮
// eventSink.success(UtilTool.resultFormatData("700000", null, null));
showResult("700000", "点击返回按钮", "");
mAuthHelper.quitLoginPage();
}
});
findViewById(R.id.tv_switch).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/// 点击切换其他按钮
showResult("700001", "切换到其他方式", "");
// eventSink.success(UtilTool.resultFormatData("700001", null, null));
mAuthHelper.quitLoginPage();
}
});
}
})
.build());
mAuthHelper.setAuthUIConfig(config.setScreenOrientation(authPageOrientation).create());
}
}

View File

@ -0,0 +1,51 @@
package com.sean.rao.ali_auth.config;
import android.content.pm.ActivityInfo;
import android.os.Build;
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
import com.mobile.auth.gatewayauth.AuthRegisterViewConfig;
import com.sean.rao.ali_auth.utils.AppUtils;
import com.sean.rao.ali_auth.utils.UtilTool;
import java.io.IOException;
public class DialogBottomConfig extends BaseUIConfig {
public DialogBottomConfig() {
super();
}
@Override
public void configAuthPage() {
int authPageOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
if (Build.VERSION.SDK_INT == 26) {
authPageOrientation = ActivityInfo.SCREEN_ORIENTATION_BEHIND;
}
updateScreenSize(authPageOrientation);
int dialogHeight = (int) (mScreenHeightDp * 0.5f);
//sdk默认控件的区域是marginTop50dp
int designHeight = dialogHeight - 50;
int unit = designHeight / 10;
mAuthHelper.addAuthRegistViewConfig("switch_msg", new AuthRegisterViewConfig.Builder()
.setView(initSwitchView(unit * 6))
.setRootViewId(AuthRegisterViewConfig.RootViewId.ROOT_VIEW_ID_BODY)
.build());
if (jsonObject.containsKey("pageBackgroundPath") && !jsonObject.getString("pageBackgroundPath").isEmpty()) {
try {
RoundedBitmapDrawable pageBackgroundDrawable = RoundedBitmapDrawableFactory.create(mContext.getResources(), UtilTool.getPathToBitmap(mContext, jsonObject.getString("pageBackgroundPath")));
pageBackgroundDrawable.setCornerRadius(AppUtils.dp2px(mContext, jsonObject.getIntValue("pageBackgroundRadius")));
config.setPageBackgroundDrawable(pageBackgroundDrawable);
} catch (IOException e) {
// eventSink.success(UtilTool.resultFormatData("500000", null, e.getMessage()));
showResult("500000", "背景处理时出现错误", e.getMessage());
}
}
mAuthHelper.setAuthUIConfig(config.setScreenOrientation(authPageOrientation).create());
}
}

View File

@ -0,0 +1,114 @@
package com.sean.rao.ali_auth.config;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.os.Build;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.mobile.auth.gatewayauth.AuthRegisterViewConfig;
import com.mobile.auth.gatewayauth.CustomInterface;
import com.sean.rao.ali_auth.utils.AppUtils;
public class DialogLandConfig extends BaseUIConfig{
private int mOldScreenOrientation;
public DialogLandConfig() {
super();
}
@Override
public void configAuthPage() {
int authPageOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
if (Build.VERSION.SDK_INT == 26) {
mOldScreenOrientation = mActivity.getRequestedOrientation();
mActivity.setRequestedOrientation(authPageOrientation);
authPageOrientation = ActivityInfo.SCREEN_ORIENTATION_BEHIND;
}
updateScreenSize(authPageOrientation);
final int dialogWidth = (int) (mScreenWidthDp * 0.63);
final int dialogHeight = (int) (mScreenHeightDp * 0.6);
//sdk默认控件的区域是marginTop50dp
int designHeight = dialogHeight - 50;
int unit = designHeight / 10;
int logBtnHeight = (int) (unit * 1.2);
final int logBtnOffsetY = unit * 3;
final View switchContainer = createLandDialogCustomSwitchView();
mAuthHelper.addAuthRegistViewConfig("number_logo", new AuthRegisterViewConfig.Builder()
.setView(initNumberView())
.setRootViewId(AuthRegisterViewConfig.RootViewId.ROOT_VIEW_ID_NUMBER)
.setCustomInterface(new CustomInterface() {
@Override
public void onClick(Context context) {
}
}).build());
mAuthHelper.addAuthRegistViewConfig("switch_other", new AuthRegisterViewConfig.Builder()
.setRootViewId(AuthRegisterViewConfig.RootViewId.ROOT_VIEW_ID_NUMBER)
.setView(switchContainer).build());
// mAuthHelper.addAuthRegisterXmlConfig(new AuthRegisterXmlConfig.Builder()
// .setLayout(R.layout.custom_land_dialog, new AbstractPnsViewDelegate() {
// @Override
// public void onViewCreated(View view) {
// findViewById(R.id.tv_title).setVisibility(View.GONE);
// findViewById(R.id.btn_close).setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// mAuthHelper.quitLoginPage();
// }
// });
// int iconTopMargin = AppUtils.dp2px(getContext(), logBtnOffsetY + 50);
// View iconContainer = findViewById(R.id.container_icon);
// RelativeLayout.LayoutParams iconLayout = (RelativeLayout.LayoutParams) iconContainer.getLayoutParams();
// iconLayout.topMargin = iconTopMargin;
// iconLayout.width = AppUtils.dp2px(getContext(), dialogWidth / 2 - 60);
// }
// })
// .build());
mAuthHelper.setAuthUIConfig(config.setScreenOrientation(authPageOrientation).create());
}
private ImageView createLandDialogPhoneNumberIcon(int leftMargin) {
ImageView imageView = new ImageView(mContext);
int size = AppUtils.dp2px(mContext, 23);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(size, size);
layoutParams.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
layoutParams.leftMargin = leftMargin;
imageView.setLayoutParams(layoutParams);
// imageView.setBackgroundResource(R.drawable.phone);
imageView.setScaleType(ImageView.ScaleType.CENTER);
return imageView;
}
private View createLandDialogCustomSwitchView() {
// View v = LayoutInflater.from(mContext).inflate(R.layout.custom_switch_other, new RelativeLayout(mContext), false);
// RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
// RelativeLayout.LayoutParams.WRAP_CONTENT);
// layoutParams.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
// v.setLayoutParams(layoutParams);
// return v;
return null;
}
@Override
public void onResume() {
super.onResume();
if (mOldScreenOrientation != mActivity.getRequestedOrientation()) {
mActivity.setRequestedOrientation(mOldScreenOrientation);
}
}
private ImageView initNumberView() {
ImageView pImageView = new ImageView(mContext);
// pImageView.setImageResource(R.drawable.phone);
pImageView.setScaleType(ImageView.ScaleType.FIT_XY);
RelativeLayout.LayoutParams pParams = new RelativeLayout.LayoutParams(AppUtils.dp2px(mContext, 30), AppUtils.dp2px(mContext, 30));
pParams.setMargins(AppUtils.dp2px(mContext, 30), 0, 0, 0);
pImageView.setLayoutParams(pParams);
return pImageView;
}
}

View File

@ -0,0 +1,106 @@
package com.sean.rao.ali_auth.config;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable;
import android.os.Build;
import android.util.Log;
import android.view.View;
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
import com.mobile.auth.gatewayauth.AuthRegisterViewConfig;
import com.sean.rao.ali_auth.common.CustomAuthUIControlClickListener;
import com.sean.rao.ali_auth.utils.AppUtils;
import com.sean.rao.ali_auth.utils.UtilTool;
import java.io.IOException;
public class DialogPortConfig extends BaseUIConfig {
/**
* 应用包名
*/
private String mPackageName;
public DialogPortConfig() {
super();
mPackageName = AppUtils.getPackageName(mActivity);
}
@Override
public void configAuthPage() {
// 注册 UI 点击事件监听用户取消勾选协议等事件
mAuthHelper.setUIClickListener(new CustomAuthUIControlClickListener());
int authPageOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
if (Build.VERSION.SDK_INT == 26) {
authPageOrientation = ActivityInfo.SCREEN_ORIENTATION_BEHIND;
}
updateScreenSize(authPageOrientation);
// 添加第三方登录按钮如果配置了的话
View switchView = initSwitchView(420);
if (switchView != null) {
mAuthHelper.addAuthRegistViewConfig("switch_msg", new AuthRegisterViewConfig.Builder()
.setView(switchView)
.setRootViewId(AuthRegisterViewConfig.RootViewId.ROOT_VIEW_ID_BODY)
.build());
}
// 弹窗背景
String bgPath = jsonObject.getString("pageBackgroundPath");
if (bgPath != null && !bgPath.isEmpty()) {
// 有背景图片加载图片并设置圆角
try {
RoundedBitmapDrawable pageBackgroundDrawable = RoundedBitmapDrawableFactory.create(
mContext.getResources(),
UtilTool.getPathToBitmap(mContext, bgPath));
pageBackgroundDrawable.setCornerRadius(
AppUtils.dp2px(mContext, jsonObject.getIntValue("pageBackgroundRadius")));
config.setPageBackgroundDrawable(pageBackgroundDrawable);
} catch (IOException e) {
showResult("500000", "背景处理时出现错误", e.getMessage());
}
} else {
// 无背景图片使用纯色背景 + 圆角
int bgColor = Color.WHITE;
if (jsonObject.containsKey("backgroundColor")) {
Object bgVal = jsonObject.get("backgroundColor");
if (bgVal instanceof Integer) {
bgColor = (Integer) bgVal;
} else if (bgVal instanceof String) {
try { bgColor = Color.parseColor((String) bgVal); } catch (Exception ignored) {}
}
}
int cornerRadius = AppUtils.dp2px(mContext, jsonObject.getIntValue("pageBackgroundRadius", 12));
GradientDrawable bgDrawable = new GradientDrawable();
bgDrawable.setColor(bgColor);
bgDrawable.setCornerRadius(cornerRadius);
config.setPageBackgroundDrawable(bgDrawable);
Log.i("DialogPortConfig", "使用纯色背景: #" + Integer.toHexString(bgColor) + ", 圆角: " + cornerRadius);
}
// 登录按钮背景如果没有设置 logBtnBackgroundPath使用蓝色圆角背景
String btnPath = jsonObject.getString("logBtnBackgroundPath");
if (btnPath == null || btnPath.isEmpty()) {
int btnRadius = AppUtils.dp2px(mContext, 22);
// 正常状态
GradientDrawable normalDrawable = new GradientDrawable();
normalDrawable.setColor(Color.parseColor("#4A90D9"));
normalDrawable.setCornerRadius(btnRadius);
// 按下状态
GradientDrawable pressedDrawable = new GradientDrawable();
pressedDrawable.setColor(Color.parseColor("#3A7BC8"));
pressedDrawable.setCornerRadius(btnRadius);
StateListDrawable btnStateDrawable = new StateListDrawable();
btnStateDrawable.addState(new int[]{android.R.attr.state_pressed}, pressedDrawable);
btnStateDrawable.addState(new int[]{}, normalDrawable);
config.setLogBtnBackgroundDrawable(btnStateDrawable);
}
mAuthHelper.setAuthUIConfig(config.setScreenOrientation(authPageOrientation).create());
}
}

View File

@ -0,0 +1,48 @@
package com.sean.rao.ali_auth.config;
import android.content.pm.ActivityInfo;
import android.os.Build;
public class FullLandConfig extends BaseUIConfig {
private int mOldScreenOrientation;
public FullLandConfig() {
super();
}
@Override
public void configAuthPage() {
// mAuthHelper.addAuthRegisterXmlConfig(new AuthRegisterXmlConfig.Builder()
// .setLayout(R.layout.custom_port_dialog_action_bar, new AbstractPnsViewDelegate() {
// @Override
// public void onViewCreated(View view) {
// findViewById(R.id.tv_title).setVisibility(View.GONE);
// findViewById(R.id.btn_close).setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// mAuthHelper.quitLoginPage();
// }
// });
// }
// })
// .build());
int authPageOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
if (Build.VERSION.SDK_INT == 26) {
mOldScreenOrientation = mActivity.getRequestedOrientation();
mActivity.setRequestedOrientation(authPageOrientation);
authPageOrientation = ActivityInfo.SCREEN_ORIENTATION_BEHIND;
}
updateScreenSize(authPageOrientation);
mAuthHelper.setAuthUIConfig(config.setScreenOrientation(authPageOrientation).create());
}
@Override
public void onResume() {
super.onResume();
if (mOldScreenOrientation != mActivity.getRequestedOrientation()) {
mActivity.setRequestedOrientation(mOldScreenOrientation);
}
}
}

View File

@ -0,0 +1,40 @@
package com.sean.rao.ali_auth.config;
import android.content.pm.ActivityInfo;
import android.os.Build;
import com.mobile.auth.gatewayauth.AuthRegisterViewConfig;
import com.sean.rao.ali_auth.common.CustomAuthUIControlClickListener;
public class FullPortConfig extends BaseUIConfig {
private final String TAG = "全屏竖屏样式";
public FullPortConfig() {
super();
}
@Override
public void configAuthPage() {
mAuthHelper.setUIClickListener(new CustomAuthUIControlClickListener());
//添加自定义切换其他登录方式
mAuthHelper.addAuthRegistViewConfig("switch_msg", new AuthRegisterViewConfig.Builder()
.setView(initSwitchView(420))
.setRootViewId(AuthRegisterViewConfig.RootViewId.ROOT_VIEW_ID_BODY)
// .setCustomInterface(new CustomInterface() {
// @Override
// public void onClick(Context context) {
// JSONObject jsonObj = new JSONObject();
// jsonObj.put("code", "7000001");
// jsonObj.put("data", "");
// jsonObj.put("msg", "切换到短信登录方式");
// eventSink.success(jsonObj);
// }
// })
.build());
int authPageOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
if (Build.VERSION.SDK_INT == 26) {
authPageOrientation = ActivityInfo.SCREEN_ORIENTATION_BEHIND;
}
mAuthHelper.setAuthUIConfig(config.setScreenOrientation(authPageOrientation).create());
}
}

View File

@ -0,0 +1,367 @@
package com.sean.rao.ali_auth.login;
import android.app.Activity;
import android.graphics.Color;
import android.util.Log;
import androidx.annotation.IntRange;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.mobile.auth.gatewayauth.AuthUIConfig;
import com.mobile.auth.gatewayauth.PhoneNumberAuthHelper;
import com.mobile.auth.gatewayauth.PreLoginResultListener;
import com.mobile.auth.gatewayauth.ResultCode;
import com.mobile.auth.gatewayauth.TokenResultListener;
import com.mobile.auth.gatewayauth.model.TokenRet;
import com.sean.rao.ali_auth.common.LoginParams;
import com.sean.rao.ali_auth.config.BaseUIConfig;
import com.sean.rao.ali_auth.utils.UtilTool;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import io.flutter.plugin.common.EventChannel;
/**
* 进app直接登录的场景
*/
public class OneKeyLoginPublic extends LoginParams {
private static final String TAG = OneKeyLoginPublic.class.getSimpleName();
public OneKeyLoginPublic(Activity activity, EventChannel.EventSink _eventSink, Object arguments){
mActivity = activity;
mContext = activity.getBaseContext();
eventSink = _eventSink;
jsonObject = formatParmas(arguments);
config = getFormatConfig(jsonObject);
// 初始化SDK
sdkInit();
mUIConfig = BaseUIConfig.init(jsonObject.getIntValue("pageType"));
if (jsonObject.getBooleanValue("isDelay")) {
} else {
// 非延时的情况下需要判断是否给予登录
mAuthHelper.quitLoginPage();
oneKeyLogin();
}
}
/**
* 初始化SDK
*/
private void sdkInit() {
mTokenResultListener=new TokenResultListener() {
@Override
public void onTokenSuccess(String s) {
sdkAvailable = true;
try {
Log.i(TAG, "checkEnvAvailable" + s);
TokenRet tokenRet = TokenRet.fromJson(s);
if (ResultCode.CODE_ERROR_ENV_CHECK_SUCCESS.equals(tokenRet.getCode())) {
/// 延时登录的情况下加速拉起一键登录页面
if (jsonObject.getBooleanValue("isDelay")) {
accelerateLoginPage(5000);
}
}
if (ResultCode.CODE_SUCCESS.equals(tokenRet.getCode())) {
Log.i("TAG", "获取token成功" + s);
mAuthHelper.setAuthListener(null);
}
showResult(tokenRet.getCode(), null, tokenRet.getToken());
} catch (Exception e) {
e.fillInStackTrace();
}
}
@Override
public void onTokenFailed(String s) {
sdkAvailable = false;
mAuthHelper.hideLoginLoading();
Log.e(TAG, "获取token失败" + s);
try {
TokenRet tokenRet = TokenRet.fromJson(s);
List<String> skip = Collections.singletonList(ResultCode.CODE_ERROR_USER_SWITCH);
if (!skip.contains(tokenRet.getCode())) {
showResult(tokenRet.getCode(), tokenRet.getMsg(),null);
}
} catch (Exception e) {
e.fillInStackTrace();
}
mAuthHelper.setAuthListener(null);
}
};
mAuthHelper=PhoneNumberAuthHelper.getInstance(mContext, mTokenResultListener);
mAuthHelper.getReporter().setLoggerEnable(jsonObject.getBooleanValue("isDebug"));
mAuthHelper.setAuthSDKInfo(jsonObject.getString("androidSk"));
// 授权页是否跟随系统深色模式
mAuthHelper.setAuthPageUseDayLight(jsonObject.getBooleanValue("authPageUseDayLight", false));
// 横屏水滴屏全屏适配
mAuthHelper.keepAuthPageLandscapeFullSreen(jsonObject.getBooleanValue("autoQuitPage", false));
// 用户控制返回键及左上角返回按钮效果, 是否自动退出授权页面false时由用户自己控制
if (!jsonObject.getBooleanValue("autoQuitPage", false)) {
mAuthHelper.userControlAuthPageCancel();
}
// SDK内置所有界面隐藏底部导航栏
if (jsonObject.getBooleanValue("keepAllPageHideNavigationBar", false)) {
mAuthHelper.keepAllPageHideNavigationBar();
}
// 授权页物理返回键禁用
mAuthHelper.closeAuthPageReturnBack(jsonObject.getBooleanValue("closeAuthPageReturnBack", false));
/// 延时的情况下进行预取号加快拉取授权页面
if (jsonObject.getBooleanValue("isDelay")) {
mAuthHelper.checkEnvAvailable(PhoneNumberAuthHelper.SERVICE_TYPE_LOGIN);
}
}
/**
* 延时登录操作
* @param timeout
*/
public void startLogin(int timeout){
if (sdkAvailable) {
mAuthHelper.quitLoginPage();
getLoginToken(timeout);
} else {
Log.e(TAG, "SDK环境检查未通过无法拉起授权页");
showResult("600002", "SDK环境不可用请检查网络和SIM卡", null);
}
}
/**
* 返回默认上网卡运营商
* @param
* @return CMCC(移动)CUCC(联通)CTCC(电信)
*/
public String getCurrentCarrierName(){
return mAuthHelper.getCurrentCarrierName();
}
/**
* 进入app就需要登录的场景使用
*/
private void oneKeyLogin() {
mUIConfig.configAuthPage();
mAuthHelper.getLoginToken(mActivity, 5000);
}
/**
* 在不是一进app就需要登录的场景 建议调用此接口 加速拉起一键登录页面
* 等到用户点击登录的时候 授权页可以秒拉
* 预取号的成功与否不影响一键登录功能所以不需要等待预取号的返回
* @param timeout
*/
private void accelerateLoginPage(int timeout) {
mAuthHelper.accelerateLoginPage(timeout, new PreLoginResultListener() {
@Override
public void onTokenSuccess(String s) {
Log.e(TAG, "预取号成功: " + s);
showResult("600016", null, s);
}
@Override
public void onTokenFailed(String s, String s1) {
Log.e(TAG, "预取号失败:" + ", " + s1);
JSONObject jsonDataObj = new JSONObject();
jsonDataObj.put("name", s);
jsonDataObj.put("name1", s1);
showResult("600012", null, jsonDataObj);
}
});
}
/**
* 拉起授权页
* @param timeout 超时时间
*/
public void getLoginToken(int timeout) {
try {
Log.i(TAG, "configAuthPage 开始配置授权页...");
mUIConfig.configAuthPage();
Log.i(TAG, "configAuthPage 配置完成");
} catch (Exception e) {
Log.e(TAG, "configAuthPage 异常: " + e.getMessage(), e);
showResult("600002", "授权页配置异常: " + e.getMessage(), null);
return;
}
mTokenResultListener = new TokenResultListener() {
@Override
public void onTokenSuccess(String s) {
TokenRet tokenRet = TokenRet.fromJson(s);
try {
if (ResultCode.CODE_START_AUTHPAGE_SUCCESS.equals(tokenRet.getCode())) {
Log.i(TAG, "唤起授权页成功:" + s);
}
showResult(tokenRet.getCode(), tokenRet.getMsg(),tokenRet.getToken());
if (ResultCode.CODE_SUCCESS.equals(tokenRet.getCode())) {
Log.i(TAG, "获取token成功" + s);
mAuthHelper.setAuthListener(null);
}
} catch (Exception e) {
e.fillInStackTrace();
}
}
@Override
public void onTokenFailed(String s) {
Log.e(TAG, "获取token失败" + s);
//如果环境检查失败 使用其他登录方式
try {
TokenRet tokenRet = TokenRet.fromJson(s);
showResult(tokenRet.getCode(), tokenRet.getMsg(),null);
} catch (Exception e) {
e.fillInStackTrace();
}
// 失败时也不关闭
mAuthHelper.setAuthListener(null);
}
};
mAuthHelper.setAuthListener(mTokenResultListener);
mAuthHelper.getLoginToken(mActivity, timeout);
}
/**
* SDK环境检查函数检查终端是否持号码认证通过TokenResultListener返回code
* type 1本机号码校验 2: 键登录
* 600024 终端持认证
* 600013 系统维护功能不可
*/
public void checkEnvAvailable(@IntRange(from = 1, to = 2) int type){
mAuthHelper.checkEnvAvailable(type);
}
/**
* 获取授权页协议勾选框选中状态
*/
public boolean queryCheckBoxIsChecked(){
return mAuthHelper.queryCheckBoxIsChecked();
}
/**
* 设置授权页协议勾选框选中状态
*
* @param paramBoolean勾选框选中状态
*/
public boolean setCheckBoxIsChecked(){
mAuthHelper.setProtocolChecked(true);
return true;
}
/**
* 退出授权页面
*/
public void quitPage(){
mAuthHelper.quitLoginPage();
}
/**
* 结束授权页loading dialog
*/
public void hideLoading(){
mAuthHelper.hideLoginLoading();
}
/**
* 处理参数对参数进行处理包含colorPath
* @param parmas
* @return
*/
private JSONObject formatParmas(Object parmas){
JSONObject formatData = JSONObject.parseObject(JSONObject.toJSONString(parmas));
for (Map.Entry<String, Object> entry : formatData.entrySet()) {
String key = entry.getKey();
String keyLower = key.toLowerCase();
String strValue = formatData.getString(key);
// 判断是否是颜色代码
if (keyLower.contains("color") && strValue != null && strValue.contains("#")) {
try {
formatData.put(key, Color.parseColor(strValue));
} catch (Exception e) {
Log.w(TAG, "颜色解析失败: " + key + " = " + strValue, e);
}
}
// 判断是否是路径字段排除按钮状态背景 logBtnBackgroundPath
else if (
!key.contains("logBtnBackgroundPath") &&
keyLower.contains("path") &&
strValue != null &&
!strValue.isEmpty() &&
!strValue.contains("http")
) {
formatData.put(key, UtilTool.flutterToPath(strValue));
}
}
return formatData;
}
/**
* 对配置参数进行格式化并且转换
* @param jsonObject
* @return
*/
private AuthUIConfig.Builder getFormatConfig(JSONObject jsonObject){
AuthUIConfig.Builder config = JSON.parseObject(JSONObject.toJSONString(jsonObject), AuthUIConfig.Builder.class);
// 设置按钮的背景
// 20230518 修正错误 setLoadingBackgroundPath -> setLogBtnBackgroundPath
if (jsonObject.getString("logBtnBackgroundPath") != null && jsonObject.getString("logBtnBackgroundPath").contains(",")) {
config.setLogBtnBackgroundDrawable(UtilTool.getStateListDrawable(mContext, jsonObject.getString("logBtnBackgroundPath")));
} else {
config.setLogBtnBackgroundPath(UtilTool.flutterToPath(jsonObject.getString("logBtnBackgroundPath")));
}
/**
* authPageActIn = var1;
* activityOut = var2;
*/
if(UtilTool.dataStatus(jsonObject, "authPageActIn") && UtilTool.dataStatus(jsonObject, "activityOut")){
config.setAuthPageActIn(jsonObject.getString("authPageActIn"), jsonObject.getString("activityOut"));
}
/**
* authPageActOut = var1;
* activityIn = var2;
*/
if(UtilTool.dataStatus(jsonObject, "authPageActOut") && UtilTool.dataStatus(jsonObject, "activityIn")){
config.setAuthPageActOut(jsonObject.getString("authPageActOut"), jsonObject.getString("activityIn"));
}
/**
* protocolOneName = var1;
* protocolOneURL = var2;
*/
if(UtilTool.dataStatus(jsonObject, "protocolOneName") && UtilTool.dataStatus(jsonObject, "protocolOneURL")){
config.setAppPrivacyOne(jsonObject.getString("protocolOneName"), jsonObject.getString("protocolOneURL"));
}
/**
* protocolTwoName = var1;
* protocolTwoURL = var2;
*/
if(UtilTool.dataStatus(jsonObject, "protocolTwoName") && UtilTool.dataStatus(jsonObject, "protocolTwoURL")){
config.setAppPrivacyTwo(jsonObject.getString("protocolTwoName"), jsonObject.getString("protocolTwoURL"));
}
/**
* protocolThreeName = var1;
* protocolThreeURL = var2;
*/
if(UtilTool.dataStatus(jsonObject, "protocolThreeName") && UtilTool.dataStatus(jsonObject, "protocolThreeURL")){
config.setAppPrivacyThree(jsonObject.getString("protocolThreeName"), jsonObject.getString("protocolThreeURL"));
}
/**
* protocolColor = var1;
* protocolOneColor = var2;
* protocolTwoColor = var2;
* protocolThreeColor = var2;
*/
if(UtilTool.dataStatus(jsonObject, "protocolColor") && UtilTool.dataStatus(jsonObject, "protocolCustomColor")){
config.setAppPrivacyColor(jsonObject.getIntValue("protocolColor"), jsonObject.getIntValue("protocolCustomColor"));
}
return config;
}
}

View File

@ -0,0 +1,45 @@
package com.sean.rao.ali_auth.utils;
import android.content.Context;
import android.util.DisplayMetrics;
import android.view.WindowManager;
public class AppUtils extends com.nirvana.tools.core.AppUtils {
public static int dp2px(Context context, float dipValue) {
try {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
} catch (Exception e) {
return (int) dipValue;
}
}
public static int px2dp(Context context, float px) {
try {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (px / scale + 0.5f);
} catch (Exception e) {
return (int) px;
}
}
public static int getPhoneWidthPixels(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics var2 = new DisplayMetrics();
if (wm != null) {
wm.getDefaultDisplay().getMetrics(var2);
}
return var2.widthPixels;
}
public static int getPhoneHeightPixels(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics var2 = new DisplayMetrics();
if (wm != null) {
wm.getDefaultDisplay().getMetrics(var2);
}
return var2.heightPixels;
}
}

View File

@ -0,0 +1,22 @@
package com.sean.rao.ali_auth.utils;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ExecutorManager {
private static ExecutorService threadExecutor;
public static void run(Runnable var0) {
threadExecutor.execute(var0);
}
static {
threadExecutor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),
Runtime.getRuntime().availableProcessors(),
0, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10), new ThreadPoolExecutor.CallerRunsPolicy());
}
}

View File

@ -0,0 +1,27 @@
package com.sean.rao.ali_auth.utils;
import android.annotation.TargetApi;
import android.app.Activity;
import android.os.Build;
import androidx.core.content.PermissionChecker;
import java.util.ArrayList;
import java.util.List;
public class PermissionUtils {
@TargetApi(Build.VERSION_CODES.M)
public static void checkAndRequestPermissions(Activity context, int requestCode,
String... permissions) {
List<String> deniedPermissions = new ArrayList<>(permissions.length);
for(String permission:permissions) {
if(PermissionChecker.checkSelfPermission(context, permission) == PermissionChecker.PERMISSION_DENIED) {
deniedPermissions.add(permission);
}
}
if(!deniedPermissions.isEmpty()) {
String[] ps = new String[deniedPermissions.size()];
ps = deniedPermissions.toArray(ps);
context.requestPermissions(ps, requestCode);
}
}
}

View File

@ -0,0 +1,105 @@
package com.sean.rao.ali_auth.utils;
/**
* @ProjectName: ali_auth
* @Package: com.jokui.rao.auth.ali_auth
* @ClassName: StatusAll
* @Description: java类作用描述
* @Author: liys
* @CreateDate: 2/16/22 5:58 PM
* @UpdateUser: 更新者
* @UpdateDate: 2/16/22 5:58 PM
* @UpdateRemark: 更新说明
* @Version: 1.0
*/
public enum StatusAll {
Status500000("参数获取异常!", "500000"),
Status500001("请先对插件进行监听!", "500001"),
Status500002("校验成功,可进行一键登录!", "500002"),
Status500003("该接口为延时登录接口,请先初始化后再次调用该接口!", "500003"),
Status500004("插件启动监听成功, 当前SDK版本: %s", "500004"),
Status600000("获取token成功", "600000"),
Status600001("唤起授权页成功!", "600001"),
Status600002("唤起授权⻚失败!建议切换到其他登录⽅式", "600002"),
Status600004("获取运营商配置信息失败!创建⼯单联系⼯程师", "600004"),
Status600005("⼿机终端不安全!切换到其他登录⽅式", "600005"),
Status600007("未检测到sim卡⽤户检查 SIM 卡后重试", "600007"),
Status600008("蜂窝⽹络未开启!⽤户开启移动⽹络后重试", "600008"),
Status600009("⽆法判断运营商! 创建⼯单联系⼯程师", "600009"),
Status600010("未知异常创建!⼯单联系⼯程师", "600010"),
Status600011("获取token失败切换到其他登录⽅式", "600011"),
Status600012("预取号失败!", "600012"),
Status600013("运营商维护升级!该功能不可⽤创建⼯单联系⼯程师", "600013"),
Status600014("运营商维护升级!该功能已达最⼤调⽤次创建⼯单联系⼯程师", "600014"),
Status600015("接⼝超时!切换到其他登录⽅式", "600011"),
Status600016("预取号成功!", "600016"),
Status600017("AppID、Appkey解析失败! 秘钥未设置或者设置错误,请先检查秘钥信息,如果⽆法解决问题创建⼯单联系⼯程师", "600017"),
Status600018("请先初始化SDK", "600018"),
Status600019("用户点击第三方按钮!", "600019"),
Status600021("点击登录时检测到运营商已切换!⽤户退出授权⻚,重新登录", "600021"),
Status600023("加载⾃定义控件异常!检查⾃定义控件添加是否正确", "600023"),
Status600024("终端环境检查⽀持认证", "600024"),
Status600025("终端检测参数错误检查传⼊参数类型与范围是否正确", "600025"),
Status600026("授权⻚已加载时不允许调⽤加速或预取号接⼝检查是否有授权⻚拉起后去调⽤preLogin或者accelerateAuthPage的接⼝该⾏为不允许", "600026"),
Status700000("用户取消登录", "700000"),
Status700001("用户切换其他登录方式", "700001"),
Status700002("用户点击登录按钮", "700002"),
Status700003("用户勾选协议选项", "700003"),
Status700004("用户点击协议富文本", "700004"),
Status700006("点击一键登录拉起授权页二次弹窗", "700006"),
Status700007("隐私协议二次弹窗关闭", "700007"),
Status700008("点击隐私协议二次弹窗上同意并继续", "700008"),
Status700009("点击隐私协议二次弹窗上的协议富文本文字", "700009"),
Status700010("中断页面消失时suspendDisMissVC设置为YES时点击左上角返回按钮透出的状态码", "700010"),
Status700020("授权页已销毁", "700020");
private String name;
private String value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
// 构造方法
StatusAll(String name, String value) {
this.name = name;
this.value = value;
}
// 普通方法
public static String getName(String value) {
for (StatusAll t : StatusAll.values()) {
if (t.getValue().equals(value)) {
return t.name;
}
}
return null;
}
/**
* 通过value取枚举
* @param valueKey
* @return
*/
public static StatusAll getStatusByValue(String valueKey){
for (StatusAll enums : StatusAll.values()) {
if (enums.getValue().equals(valueKey)) {
return enums;
}
}
return null;
}
}

View File

@ -0,0 +1,161 @@
package com.sean.rao.ali_auth.utils;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable;
import android.text.TextUtils;
import com.alibaba.fastjson2.JSONObject;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import io.flutter.FlutterInjector;
import io.flutter.embedding.engine.loader.FlutterLoader;
import io.flutter.plugin.common.MethodCall;
/**
* @ProjectName: android
* @Package: com.sean.rao.ali_auth.utils
* @ClassName: UtilTool
* @Description: java类作用描述
* @Author: liys
* @CreateDate: 5/11/22 3:33 PM
* @UpdateUser: 更新者
* @UpdateDate: 5/11/22 3:33 PM
* @UpdateRemark: 更新说明
* @Version: 1.0
*/
public class UtilTool {
/**
* 判断数据类型
* @param data
* @param key
* @return
*/
public static boolean dataStatus(JSONObject data, String key ){
if(data.containsKey(key) && data.get(key) != null){
if((data.get(key) instanceof Float) || (data.get(key) instanceof Double) && (double) data.get(key) > -1){
return true;
} else if((data.get(key) instanceof Integer) || (data.get(key) instanceof Number) && (int) data.get(key) > -1){
return true;
} else if((data.get(key) instanceof Boolean) && (boolean) data.get(key)){
return true;
} else if((data.get(key) instanceof String) && !((String) data.get(key)).equals("")){
return true;
} else {
return false;
}
} else {
return false;
}
}
/**
* flutter 路径转换
* @param fluPath
* @return
*/
public static String flutterToPath(@Nullable Object fluPath){
FlutterLoader flutterLoader = FlutterInjector.instance().flutterLoader();
return flutterLoader.getLookupKeyForAsset(String.valueOf(fluPath));
}
/**
* 获取key
* @param call
* @param key
* @return
*/
public static Object getValueByKey(MethodCall call, String key) {
if (call != null && call.hasArgument(key)) {
return call.argument(key);
} else {
return null;
}
}
/**
* 创建有状态的按钮
* @param mContext
* @param btnPathImage
* @return
*/
public static Drawable getStateListDrawable(Context mContext, String btnPathImage) {
StateListDrawable stateListDrawable = new StateListDrawable();
if (!btnPathImage.contains(",")) {
return stateListDrawable;
}
try{
List<String> btnPathList = Arrays.asList(btnPathImage.split(","));
// 正常状态下的Drawable
BitmapDrawable drawable_p = getBitmapToBitmapDrawable(mContext, flutterToPath(btnPathList.get(0)));
// 按下和获取焦点是的Drawable
BitmapDrawable drawable_n = getBitmapToBitmapDrawable(mContext, flutterToPath(btnPathList.get(1)));
// 被禁用时的Drawable
BitmapDrawable drawable_b = getBitmapToBitmapDrawable(mContext, flutterToPath(btnPathList.get(2)));
stateListDrawable.addState(new int[]{android.R.attr.state_activated, android.R.attr.state_pressed}, drawable_n);
stateListDrawable.addState(new int[]{android.R.attr.state_activated, -android.R.attr.state_pressed}, drawable_p);
stateListDrawable.addState(new int[]{-android.R.attr.state_activated, -android.R.attr.state_pressed}, drawable_b);
stateListDrawable.addState(new int[]{-android.R.attr.state_activated, android.R.attr.state_pressed}, drawable_n);
} catch (IOException e) {
e.fillInStackTrace();
}
return stateListDrawable;
}
/**
* 将bitmap数据转换为drawable
* @param mContext
* @param path
* @return
*/
public static BitmapDrawable getBitmapToBitmapDrawable(Context mContext, String path) throws IOException {
// 正常状态下的Drawable
return new BitmapDrawable(mContext.getResources(), getPathToBitmap(mContext, path));
}
/**
* 获取本地图片转换为bitmap
* @param mContext
* @param path
* @return
*/
public static Bitmap getPathToBitmap(Context mContext, String path) throws IOException {
AssetManager assetManager = mContext.getAssets();
InputStream fileDescriptor = assetManager.open(path);
Bitmap bitmap = BitmapFactory.decodeStream(fileDescriptor);
return bitmap;
}
/**
* 返回数据封装
* @param code
* @param msg
* @param jsonDataObj
* @return
*/
public static JSONObject resultFormatData(String code, @Nullable String msg, @Nullable Object jsonDataObj){
JSONObject jsonObj = new JSONObject();
jsonObj.put("code", code);
jsonObj.put("msg", msg != null && !msg.isEmpty() ? msg : StatusAll.getName(code));
jsonObj.put("data", jsonDataObj != null ? jsonDataObj : "");
jsonObj.put("isChecked", false);
return jsonObj;
}
}

View File

@ -1,22 +0,0 @@
package com.sean.rao.ali_auth
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
class AliAuthPlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
private lateinit var channel: MethodChannel
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(binding.binaryMessenger, "ali_auth")
channel.setMethodCallHandler(this)
}
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
result.notImplemented()
}
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
}

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromYDelta="100%"
android:toYDelta="0%"
android:duration="800"
/>
</set>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="800"
android:fromYDelta="0%"
android:toYDelta="100%"
/>
</set>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/colorPrimary" android:state_checked="true"/>
<item android:color="@color/colorPrimary" android:state_pressed="true"/>
<item android:color="@color/md_grey_700"/>
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary"
android:orientation="vertical">
<Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:title="自定义协议页"
android:titleTextColor="@android:color/white"
tools:targetApi="lollipop" />
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fly_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>

View File

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/navColor">
<ImageView
android:id="@+id/btn_back"
android:layout_width="20dp"
android:layout_height="20dp"
android:background="@drawable/icon_close"
android:scaleType="center"
android:layout_centerVertical="true"
android:cropToPadding="true"
android:layout_marginLeft="12dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textSize="18sp"
android:textColor="@color/white"
android:text="@string/custom_title"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="50dp"
android:orientation="vertical">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerHorizontal="true"
android:background="@drawable/phone" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="70dp"
android:text="@string/custom_slogan"
android:textColor="@color/black"
android:textSize="20sp" />
<TextView
android:id="@+id/tv_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="350dp"
android:text="@string/switch_msg"
android:textSize="18sp" />
</RelativeLayout>
</LinearLayout>
</RelativeLayout>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="black">#FF000000</color>
<color name="md_grey_700">#616161</color>
<color name="white">#ffffffff</color>
<color name="navColor">#ff026ED2</color>
</resources>

View File

@ -0,0 +1,8 @@
<resources>
<string name="app_name">号码认证Demo</string>
<string name="switch_msg">切换到短信登录页面</string>
<string name="custom_title">自定义标题</string>
<string name="custom_slogan">自定义Slogan</string>
<string name="custom_toast">同意服务条款才可以登录</string>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true" >
<domain includeSubdomains="true">enrichgw.10010.com</domain> <!-- 联通内部5G请求域名开发者需要添加 -->
<domain includeSubdomains="true">onekey.cmpassport.com</domain> <!-- 移动内部请求域名,开发者需要添加 -->
<domain includeSubdomains="true">140.205.57.248</domain> <!-- demo测试ip开发者无需添加 -->
<domain includeSubdomains="true">gw.api.tbsandbox.com</domain> <!-- demo测试域名开发者无需添加 -->
<domain includeSubdomains="true">m.aliyun.com</domain> <!-- demo测试域名开发者无需添加 -->
</domain-config>
</network-security-config>

View File

@ -0,0 +1,38 @@
.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
/Flutter/ephemeral/
/Flutter/flutter_export_environment.sh

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 950 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

View File

@ -0,0 +1,43 @@
//
// AliAuthEnum.好的.h
// Pods
//
// Created by Yau的MacBook on 2022/5/19.
// Copyright © 2022 Yau的MacBook. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface AliAuthEnum : NSObject
+ (NSDictionary *)initData;
+ (NSDictionary *)keyPair;
@end
// FOUNDATION_EXPORT NSString * const StatusAll;
typedef NS_ENUM(NSUInteger, PNSBuildModelStyle) {
//全屏
PNSBuildModelStylePortrait,
PNSBuildModelStyleLandscape,
//PNSBuildModelStyleAutorotate,
//弹窗
PNSBuildModelStyleAlertPortrait,
PNSBuildModelStyleAlertLandscape,
// PNSBuildModelStyleAlertAutorotate,
//底部弹窗
PNSBuildModelStyleSheetPortrait,
//DIY 动画
PNSDIYAlertPortraitFade,
PNSDIYAlertPortraitDropDown,
// PNSDIYAlertPortraitBounce,
// PNSDIYPortraitFade,
// PNSDIYPortraitScale,
PNSBuildModelStyleGifBackground,
//other
PNSBuildModelStyleVideoBackground,
PNSBuildModelStylePicBackground,
};

View File

@ -0,0 +1,129 @@
//
// AliAuthEnum.m
// ali_auth
//
// Created by YauMacBook on 2022/5/19.
// Copyright © 2022 YauMacBook. All rights reserved.
//
#import "AliAuthEnum.h"
@implementation AliAuthEnum : NSObject
static NSDictionary * StatusAll = nil;
+ (NSDictionary *)initData {
if (StatusAll == nil) {
StatusAll = @{
@"500000": @"参数获取异常!",
@"500001": @"密钥不能为空, 请先检查密钥是否设置!",
@"500002": @"校验成功,可进行一键登录!",
@"500003": @"该接口为延时登录接口,请先初始化后再次调用该接口!",
@"500004": @"插件启动监听成功, 当前SDK版本: %@",
@"600000": @"获取token成功",
@"600001": @"唤起授权页成功!",
@"600002": @"唤起授权⻚失败!建议切换到其他登录⽅式",
@"600004": @"获取运营商配置信息失败!创建⼯单联系⼯程师",
@"600005": @"⼿机终端不安全!切换到其他登录⽅式",
@"600007": @"未检测到sim卡⽤户检查 SIM 卡后,",
@"600008": @"蜂窝⽹络未开启!⽤户开启移动⽹络后重试",
@"600009": @"⽆法判断运营商! 创建⼯单联系⼯程师",
@"600010": @"未知异常创建!⼯单联系⼯程师",
@"600011": @"获取token失败切换到其他登录⽅式",
@"600012": @"预取号失败!",
@"600013": @"运营商维护升级!该功能不可⽤创建⼯单联系⼯程师",
@"600014": @"运营商维护升级!该功能已达最⼤调⽤次创建⼯单联系⼯程师",
@"600015": @"接⼝超时!切换到其他登录⽅式",
@"600016": @"预取号成功!",
@"600017": @"AppID、Appkey解析失败! 秘钥未设置或者设置错误,请先检查秘钥信息,如果⽆法解决问题创建⼯单联系⼯程师",
@"600018": @"请先初始化SDK",
@"600019": @"用户点击第三方按钮!",
@"600021": @"点击登录时检测到运营商已切换!⽤户退出授权⻚,重新登录",
@"600023": @"加载⾃定义控件异常!检查⾃定义控件添加是否正确",
@"600024": @"终端环境检查⽀持认证",
@"600025": @"终端检测参数错误检查传⼊参数类型与范围是否正确",
@"600026": @"授权⻚已加载时不允许调⽤加速或预取号接⼝检查是否有授权⻚拉起后去调⽤preLogin或者accelerateAuthPage的接⼝该⾏为不允许",
@"700000": @"用户取消登录",
@"700001": @"用户切换其他登录方式",
@"700002": @"用户点击登录按钮",
@"700003": @"用户勾选协议选项",
@"700004": @"用户点击协议富文本",
@"700006": @"点击一键登录拉起授权页二次弹窗",
@"700007": @"隐私协议二次弹窗关闭",
@"700008": @"点击隐私协议二次弹窗上同意并继续",
@"700009": @"点击隐私协议二次弹窗上的协议富文本文字",
@"700010": @"中断页面消失时suspendDisMissVC设置为YES时点击左上角返回按钮透出的状态码",
@"700020": @"授权页已销毁!",
};
}
return StatusAll;
}
+ (NSDictionary *)keyPair {
return @{
/// 1
@"isStatusBarHidden": @"prefersStatusBarHidden",
@"lightColor": @"preferredStatusBarStyle",
/// 2
@"navHidden": @"navIsHidden",
@"backgroundColor": @"alertContentViewColor",
@"navReturnImgPath": @"navBackImage",
@"navReturnHidden": @"hideNavBackItem",
/// 3Logo
@"logoImgPath": @"logoImage",
@"logoHidden": @"logoIsHidden",
/// 4Slogan
@"sloganHidden": @"sloganIsHidden",
/// 5
@"numberSize": @"numberFont",
/// 6
/// 7
@"switchAccHidden": @"changeBtnIsHidden",
@"switchAccText": @"changeBtnTitle",
/// 9
@"checkboxHidden": @"checkBoxIsHidden",
@"checkBoxHeight": @"checkBoxWH",
@"privacyState": @"checkBoxIsChecked",
@"privacyTextSize": @"privacyFont",
@"protocolGravity": @"privacyAlignment",
@"protocolOwnOneColor": @"privacyOneColor",
@"protocolOwnTwoColor": @"privacyTwoColor",
@"protocolOwnThreeColor": @"privacyThreeColor",
@"protocolOwnColor": @"privacyOperatorColor",
@"privacyBefore": @"privacyPreText",
@"privacyEnd": @"privacySufText",
@"vendorPrivacyPrefix": @"privacyOperatorPreText",
@"vendorPrivacySuffix": @"privacyOperatorSufText",
@"privacyConectTexts": @"privacyConectTexts",
///
@"webNavColor": @"privacyNavColor",
@"webNavTextColor": @"privacyNavTitleColor",
@"webNavTextSize": @"privacyNavTitleFont",
@"webNavReturnImgPath": @"privacyNavBackImage",
///
@"pageBackgroundPath": @"backgroundImage",
///
@"dialogCornerRadiusArray": @"alertCornerRadiusArray",
@"alertCloseImagePath": @"alertCloseImage",
///
@"privacyAlertIsNeedAutoLogin": @"privacyAlertIsNeedAutoLogin",
@"privacyAlertTitleTextSize": @"privacyAlertTitleFont",
@"privacyAlertContentVerticalMargin": @"privacyAlertLineSpaceDp",
@"privacyAlertBtnText": @"privacyAlertBtnContent",
@"privacyAlertBtnTextSize": @"privacyAlertButtonFont",
@"privacyAlertContentTextSize": @"privacyAlertContentFont",
@"privacyAlertBtnBackgroundImgPath": @"privacyAlertBtnBackgroundImages",
@"privacyAlertCloseImagPath": @"privacyAlertCloseButtonImage",
@"privacyAlertCloseBtnShow": @"privacyAlertCloseButtonIsNeedShow",
@"privacyAlertBefore": @"privacyAlertPreText",
@"privacyAlertEnd": @"privacyAlertSufText",
@"privacyAlertProtocolNameUseUnderLine": @"privacyAlertContentUnderline",
};
}
#pragma mark --
typedef NS_ENUM(NSInteger, MBProgressHUBPosition) {
MBProgressHUBPositionTop, //
MBProgressHUBPositionCenter, //
MBProgressHUBPositionBottom //
};
@end

View File

@ -0,0 +1,5 @@
#import <Flutter/Flutter.h>
@interface AliAuthPlugin : NSObject<FlutterPlugin>
@end

View File

@ -0,0 +1,683 @@
#import "AliAuthPlugin.h"
#import <UIKit/UIKit.h>
#import "AliAuthEnum.h"
#import "MJExtension.h"
#import <ATAuthSDK/ATAuthSDK.h>
//#import "MBProgressHUD.h"
#import "PNSBuildModelUtils.h"
#import "NSDictionary+Utils.h"
#import "UIColor+Hex.h"
#import <AuthenticationServices/AuthenticationServices.h>
#define TX_SCREEN_HEIGHT [[UIScreen mainScreen] bounds].size.height
#define TX_SCREEN_WIDTH [[UIScreen mainScreen] bounds].size.width
bool bool_true = true;
bool bool_false = false;
//
//#define NSLog(format,...) printf("%s",[[NSString stringWithFormat:(format), ##__VA_ARGS__] UTF8String])
/// ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding
/// authorizationController.delegate = self; authorizationController.presentationContextProvider = self;
@interface AliAuthPlugin()<UIApplicationDelegate, FlutterStreamHandler, ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding>
@property (nonatomic, strong) UINavigationController *navigationController;
@end
@implementation AliAuthPlugin{
FlutterEventSink _eventSink;
FlutterResult _result;
FlutterMethodCall * _callData;
TXCustomModel * _model;
Boolean _isChecked;
Boolean _isHideToast;
}
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
AliAuthPlugin* instance = [[AliAuthPlugin alloc] init];
FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:@"ali_auth" binaryMessenger: [registrar messenger]];
FlutterEventChannel* chargingChannel = [FlutterEventChannel eventChannelWithName:@"ali_auth/event" binaryMessenger: [registrar messenger]];
[chargingChannel setStreamHandler: instance];
[registrar addMethodCallDelegate:instance channel: channel];
//demo使
[[AliAuthPlugin alloc] httpAuthority];
}
#pragma mark - IOS flutter eventChannel start
- (FlutterError*)onListenWithArguments:(id)arguments eventSink:(FlutterEventSink)eventSink {
if (_eventSink == nil) {
_eventSink = eventSink;
/** */
NSString *version = [[TXCommonHandler sharedInstance] getVersion];
NSDictionary *dict = @{ @"resultCode": @"500004", @"msg": version };
[self showResultMsg: dict msg:version];
}
return nil;
}
- (FlutterError*)onCancelWithArguments:(id)arguments {
[[NSNotificationCenter defaultCenter] removeObserver:self];
_eventSink = nil;
return nil;
}
// eventChannel end
#pragma mark -
-(void)httpAuthority{
NSURL *url = [NSURL URLWithString:@"https://www.baidu.com/"];//
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error == nil) {
// NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
NSLog(@"联网成功!");
} else {
NSLog(@"联网失败!");
}
}];
[dataTask resume];
}
#pragma mark - flutter oc eventChannel start
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
// SDK
_callData = call;
_result = result;
if ([@"getPlatformVersion" isEqualToString:call.method]) {
result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
}
else if ([@"getCurrentCarrierName" isEqualToString:call.method]) {
//
result([TXCommonUtils getCurrentCarrierName]);
}
// SDK
else if ([@"initSdk" isEqualToString:call.method]) {
_isHideToast = [call.arguments boolValueForKey: @"isHideToast" defaultValue: NO];
if (_eventSink == nil) {
result(@{ @"code": @"500001", @"msg": @"请先对插件进行监听!" });
} else {
[self initSdk];
}
}
//
else if ([@"login" isEqualToString:call.method]) {
if(_model == nil){
NSDictionary *dict = @{ @"resultCode": @"500003" };
[self showResult: dict];
return;
}
self->_isChecked = [_callData.arguments boolValueForKey: @"privacyState" defaultValue: NO];
[self loginWithModel: _model complete:^{}];
}
else if ([@"checkEnvAvailable" isEqualToString:call.method]) {
[self checkVerifyEnable:call result:result];
}
else if ([@"queryCheckBoxIsChecked" isEqualToString:call.method]) {
BOOL status = [[TXCommonHandler sharedInstance] queryCheckBoxIsChecked];
result(@(status));
}
else if ([@"setCheckboxIsChecked" isEqualToString:call.method]) {
[[TXCommonHandler sharedInstance] setCheckboxIsChecked:YES];
result(@(bool_true));
}
else if ([@"checkCellularDataEnable" isEqualToString:call.method]) {
[self checkCellularDataEnable:call result:result];
}
else if ([@"preLogin" isEqualToString:call.method]) {
[self getPreLogin:call result:result];
}
else if ([@"quitPage" isEqualToString:call.method]) {
[[TXCommonHandler sharedInstance] cancelLoginVCAnimated:YES complete:nil];
}
else if ([@"hideLoading" isEqualToString:call.method]) {
[[TXCommonHandler sharedInstance] hideLoginLoading];
}
else if ([@"appleLogin" isEqualToString:call.method]) {
[self handleAuthorizationAppleIDButtonPress:call result:result];
}
else if ([@"openPage" isEqualToString:call.method]) {
// 1.flutter homeflutter
FlutterViewController* flutterViewController = [
[FlutterViewController alloc] initWithProject:nil
initialRoute:[call.arguments stringValueForKey: @"pageRoute" defaultValue: @"/"]
nibName:nil
bundle:nil
];
// 2.
flutterViewController.modalPresentationStyle = UIModalPresentationFullScreen;
[[self findCurrentViewController] presentViewController:flutterViewController animated: YES completion:nil];
}
else {
result(FlutterMethodNotImplemented);
}
}
#pragma mark - SDK
- (void)initSdk {
NSDictionary *dic = _callData.arguments;
// _model = [TXCustomModel mj_objectWithKeyValues: dic];
if ([[dic stringValueForKey: @"iosSk" defaultValue: @""] isEqualToString:@""]) {
NSDictionary *dict = @{ @"resultCode": @"500000" };
[self showResult: dict];
}
else {
NSString *secret = [dic stringValueForKey: @"iosSk" defaultValue: @""];
/** model */
_model = [PNSBuildModelUtils buildModelWithStyle: dic target:self selector:@selector(btnClick:)];
//1. sdksecret
[[TXCommonHandler sharedInstance] setAuthSDKInfo:secret complete:^(NSDictionary * _Nonnull resultDic) {
//2. check
[[TXCommonHandler sharedInstance] checkEnvAvailableWithAuthType:PNSAuthTypeLoginToken complete:^(NSDictionary * _Nullable checkDic) {
if ([PNSCodeSuccess isEqualToString:[checkDic objectForKey:@"resultCode"]] == YES) {
NSDictionary *dict = @{ @"resultCode": @"600024" };
[self showResult: dict];
//3.
[[TXCommonHandler sharedInstance] accelerateLoginPageWithTimeout: 5.0 complete:^(NSDictionary * _Nonnull resultDic) {
//4.
if ([PNSCodeSuccess isEqualToString:[resultDic objectForKey:@"resultCode"]] == YES) {
if (![dic boolValueForKey: @"isDelay" defaultValue: NO]) {
[self loginWithModel: self->_model complete:^{}];
}
NSString *carrierNam = [TXCommonUtils getCurrentCarrierName];
NSDictionary *acceleDict = @{ @"resultCode": @"600016", @"data": carrierNam };
[self showResult: acceleDict];
return;
}
[self showResult: resultDic];
}];
} else {
NSMutableDictionary *result = [NSMutableDictionary dictionaryWithDictionary:checkDic];
[result setValue:@(bool_false) forKey: @"token"];
[self showResult: result];
}
}];
}];
}
}
/** SDK */
- (void)checkVerifyEnable:(FlutterMethodCall*)call result:(FlutterResult)result {
__weak typeof(self) weakSelf = self;
[[TXCommonHandler sharedInstance] checkEnvAvailableWithAuthType:PNSAuthTypeLoginToken complete:^(NSDictionary * _Nullable resultDic) {
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setValue: [resultDic objectForKey:@"resultCode"] forKey: @"code"];
if ([PNSCodeSuccess isEqualToString:[resultDic objectForKey:@"resultCode"]] == NO) {
[weakSelf showResult:resultDic];
[dict setValue: @(bool_false) forKey: @"data"];
} else {
[[TXCommonHandler sharedInstance] accelerateLoginPageWithTimeout:5.0 complete:^(NSDictionary * _Nonnull resultDic) {
/// NSLog(@"为后面授权页拉起加个速,加速结果:%@", resultDic);
}];
// 2G/3G/4G3G/4G4G 2G
// WiFi4G3G2GNoInternet
// NSString *networktype = [[TXCommonUtils init] getNetworktype];
// //
// NSString *carrierName = [[TXCommonUtils init] getCurrentCarrierName];
// if( [carrierName isEqual:(@"中国移动")] && [networktype isEqual:(@"2G")] && [networktype isEqual:(@"3G")] && [networktype isEqual:(@"4G")] ){
// result(@(bool_true));
// } else if( [carrierName isEqual:(@"中国联通")] && [networktype isEqual:(@"3G")] && [networktype isEqual:(@"4G")]){
// result(@(bool_true));
// } else if( [carrierName isEqual:(@"中国电信")] && [networktype isEqual:(@"4G")]){
// result(@(bool_true));
// }
// result(@(bool_false));
[dict setValue: @"终端环境检查⽀持认证" forKey: @"msg"];
[dict setValue: @"600024" forKey: @"code"];
[dict setValue: @(bool_true) forKey: @"data"];
}
[self resultData: dict];
}];
}
/** */
- (void)checkCellularDataEnable:(FlutterMethodCall*)call result:(FlutterResult)result {
bool status = [TXCommonUtils checkDeviceCellularDataEnable];
NSDictionary *dict = @{
@"code": @"1",
@"msg" : @"蜂窝网络检测",
@"data" : @(status)
};
result(dict);
}
#pragma mark - action
- (void)btnClick: (UIGestureRecognizer *) sender {
UIButton *view = (UIButton *)sender;
NSInteger index = view.tag;
NSDictionary *dict = @{
@"code": @"700005",
@"msg" : @"点击第三方登录按钮",
@"data" : [NSNumber numberWithInteger: index]
};
[self resultData: dict];
if (!self->_isChecked && !self->_isHideToast) {
NSDictionary *dic = self -> _callData.arguments;
// [self showToast: [dic stringValueForKey: @"toastText" defaultValue: @"请先阅读用户协议"]];
} else {
[[TXCommonHandler sharedInstance] cancelLoginVCAnimated: YES complete:^(void) {}];
}
}
//
- (void)getPreLogin:(FlutterMethodCall*)call result:(FlutterResult)result{
[self accelerateLogin:_model call:call result:result complete:^{}];
}
/**
* : accelerateLoginPageWithTimeout
* @brief getLoginTokenWithTimeout:controller:model:complete:
* @param timeouts3.0s0.0
* @param complete resultDic=@{resultCode:600000, msg:...}"resultCode"PNSReturnCode
*/
#pragma mark - action
- (void)accelerateLogin:(TXCustomModel *)model call:(FlutterMethodCall*)call result:(FlutterResult)result complete:(void (^)(void))completion {
float timeout = 5.0; // self.tf_timeout.text.floatValue;
__weak typeof(self) weakSelf = self;
//1. check
[[TXCommonHandler sharedInstance] checkEnvAvailableWithAuthType:PNSAuthTypeLoginToken complete:^(NSDictionary * _Nullable resultDic) {
if ([PNSCodeSuccess isEqualToString:[resultDic objectForKey:@"resultCode"]] == NO) {
[weakSelf showResult:resultDic];
return;
}
NSDictionary *dict = @{ @"resultCode": @"600024" };
[self showResult: dict];
//2.
[[TXCommonHandler sharedInstance] accelerateLoginPageWithTimeout:timeout complete:^(NSDictionary * _Nonnull resultDic) {
if ([PNSCodeSuccess isEqualToString:[resultDic objectForKey:@"resultCode"]] == NO) {
[weakSelf showResult:resultDic];
return;
}
NSDictionary *acceleDict = @{ @"resultCode": @"600016" };
[self showResult: acceleDict];
}];
}];
}
// Flutterview
-(void)handleSingleTap:(UITapGestureRecognizer *)sender{ //
NSLog(@"%@", @"我被点击了");
}
#pragma mark - action
- (void)loginWithModel:(TXCustomModel *)model complete:(void (^)(void))completion {
float timeout = 5.0; //self.tf_timeout.text.floatValue;
__weak typeof(self) weakSelf = self;
// UIWindow *window = [[UIApplication sharedApplication].delegate window];
// UIViewController * _vc = [[ViewController alloc] init];
// window.rootViewController = _vc;
UIViewController *_vc = [self findCurrentViewController];
// UIButton *pushFlutterNativePageButton = [UIButton buttonWithType:UIButtonTypeSystem];
// pushFlutterNativePageButton.frame = CGRectMake(100, 300, 300, 100);
// [pushFlutterNativePageButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
// [pushFlutterNativePageButton setTitle:@"跳转到Flutter混合原生view界面" forState:UIControlStateNormal];
// [pushFlutterNativePageButton addTarget:self action:@selector(pushFlutterNativePage) forControlEvents:UIControlEventTouchUpInside];
// [_vc.view addSubview:pushFlutterNativePageButton];
//
self->_isChecked = false;
//1. check
[[TXCommonHandler sharedInstance] checkEnvAvailableWithAuthType:PNSAuthTypeLoginToken complete:^(NSDictionary * _Nullable resultDic) {
if ([PNSCodeSuccess isEqualToString:[resultDic objectForKey:@"resultCode"]] == NO) {
[weakSelf showResult:resultDic];
return;
}
//2.
[[TXCommonHandler sharedInstance] accelerateLoginPageWithTimeout:timeout complete:^(NSDictionary * _Nonnull resultDic) {
if ([PNSCodeSuccess isEqualToString:[resultDic objectForKey:@"resultCode"]] == NO) {
[weakSelf showResult:resultDic];
return;
}
//3. Token
// loading
// [MBProgressHUD hideHUDForView:_vc.view animated:YES];
[[TXCommonHandler sharedInstance] getLoginTokenWithTimeout:timeout controller:_vc model:model complete:^(NSDictionary * _Nonnull resultDic) {
NSString *code = [resultDic objectForKey:@"resultCode"];
// UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(clickAllScreen:)];
//
// UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, _vc.view.bounds.size.width, _vc.view.bounds.size.height)];
//view
[[weakSelf findCurrentViewController].view hitTest:CGPointMake(_vc.view.bounds.size.width, _vc.view.bounds.size.height) withEvent:nil];
// [[weakSelf findCurrentViewController].view addSubview:headerView];
// Toast
if ([PNSCodeLoginControllerClickLoginBtn isEqualToString:code] && !self->_isChecked) {
} else if ([PNSCodeSuccess isEqualToString:code]) {
bool autoQuitPage = [self->_callData.arguments boolValueForKey: @"autoQuitPage" defaultValue: YES];
//
if (autoQuitPage) {
dispatch_async(dispatch_get_main_queue(), ^{
[[TXCommonHandler sharedInstance] cancelLoginVCAnimated:YES complete:nil];
});
}
} else if ([PNSCodeLoginControllerClickChangeBtn isEqualToString:code]) {
// switchCheck
NSDictionary *dic = self -> _callData.arguments;
if (!self->_isChecked && !self-> _isHideToast && [dic boolValueForKey: @"switchCheck" defaultValue: YES]) {
} else {
[[TXCommonHandler sharedInstance] cancelLoginVCAnimated:YES complete:nil];
}
} else if ([PNSCodeLoginControllerClickCheckBoxBtn isEqualToString:code]) { //
self->_isChecked = [[resultDic objectForKey:@"isChecked"] boolValue];
} else if ([PNSCodeLoginControllerClickCancel isEqualToString:code]) { //
[[TXCommonHandler sharedInstance] cancelLoginVCAnimated:YES complete:nil];
} else if ([PNSCodeCarrierChanged isEqualToString:code]) { //
[[TXCommonHandler sharedInstance] cancelLoginVCAnimated:YES complete:nil];
}
[weakSelf showResult:resultDic];
}];
}];
}];
}
#pragma mark - toast
- (void)showToast:(NSString*) message {
// NSDictionary *dic = _callData.arguments;
// UIView *view = [self findCurrentViewController].view;
// MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo: view animated:YES];
// // Set the text mode to show only text.
// hud.mode = MBProgressHUDModeText;
// hud.label.text = NSLocalizedString(message, @"温馨提示");
// //
// hud.margin = [dic floatValueForKey: @"toastPadding" defaultValue: 10];
// //
// hud.contentColor = [UIColor colorWithHex: [dic stringValueForKey: @"toastColor" defaultValue: @"#FFFFFF"] defaultValue: @"#FFFFFF"];
// //
// hud.bezelView.color = [UIColor colorWithHex: [dic stringValueForKey: @"toastBackground" defaultValue: @"#000000"] defaultValue: @"#000000"];
// //
// hud.bezelView.style = MBProgressHUDBackgroundStyleSolidColor;
//
// CGFloat offSetY = view.bounds.size.height / 2;
// NSString* toastPosition = [dic stringValueForKey: @"toastPositionMode" defaultValue: @"bottom"];
// if ([toastPosition isEqual: @"top"]) {
// CGFloat top = [dic floatValueForKey: @"toastMarginTop" defaultValue: 30.f];
// offSetY = - offSetY + view.window.safeAreaInsets.top + top;
// } else if ([toastPosition isEqual: @"bottom"]) {
// CGFloat bottom = [dic floatValueForKey: @"toastMarginBottom" defaultValue: 30.f];
// offSetY = offSetY - view.window.safeAreaInsets.bottom - bottom;
// } else if ([toastPosition isEqual: @"center"]) {
// offSetY = 0;
// }
// //
// hud.offset = CGPointMake(0.f, offSetY);
// [hud hideAnimated:YES afterDelay: [dic floatValueForKey: @"toastDelay" defaultValue: 3]];
}
-(void) resultData:(NSDictionary *)dict{
if (_eventSink != nil) {
NSMutableDictionary *mutableDict = [dict mutableCopy];
[mutableDict setObject: self->_isChecked ? @(bool_true):@(bool_false) forKey: @"isChecked"];
_eventSink(mutableDict);
}
}
#pragma mark - utils
- (void)showResult:(id __nullable)showResult {
// autoHideLoginLoading
// if (![self->_callData.arguments boolValueForKey: @"autoHideLoginLoading" defaultValue: YES]) {
// dispatch_async(dispatch_get_main_queue(), ^{
// [MBProgressHUD hideHUDForView: [self findCurrentViewController].view animated:YES];
// });
// }
NSDictionary *dict = @{
@"code": [NSString stringWithFormat: @"%@", [showResult objectForKey:@"resultCode"]],
@"msg" : [AliAuthEnum initData][[showResult objectForKey:@"resultCode"]]?:@"",
@"data" : [showResult objectForKey: @"token"]?:@"",
@"isChecked": self->_isChecked ? @(bool_true):@(bool_false)
};
[self resultData: dict];
[self showResultLog: showResult];
}
#pragma mark - utils
- (void)showResultMsg:(id __nullable)showResult msg: (NSString*)msg {
NSString *resultMsg = [NSString stringWithFormat: [AliAuthEnum initData][[showResult objectForKey:@"resultCode"]], msg]?:@"";
NSDictionary *dict = @{
@"code": [NSString stringWithFormat: @"%@", [showResult objectForKey:@"resultCode"]],
@"msg" : resultMsg,
@"data" : [showResult objectForKey: @"token"]?:@""
};
[self resultData: dict];
[self showResultLog: showResult];
}
#pragma mark - utils
- (void)showResultLog:(id __nullable)showResult {
dispatch_async(dispatch_get_main_queue(), ^{
NSString *desc = nil;
if ([showResult isKindOfClass:NSString.class]) {
desc = (NSString *)showResult;
} else {
desc = [showResult description];
// if (desc != nil) {
// desc = [NSString stringWithCString:[desc cStringUsingEncoding:NSUTF8StringEncoding] encoding:NSNonLossyASCIIStringEncoding];
// }
}
// NSLog( @"打印日志---->>%@", desc );
});
}
#pragma mark - Apple
//
- (void)handleAuthorizationAppleIDButtonPress:(FlutterMethodCall*)call result:(FlutterResult)result{
NSLog(@"点击授权---开始授权");
if (@available(iOS 13.0, *)) {
// Apple ID
ASAuthorizationAppleIDProvider *appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init];
// AppleID
ASAuthorizationAppleIDRequest *appleIDRequest = [appleIDProvider createRequest];
//
appleIDRequest.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail];
// ASAuthorizationAppleIDProvider
ASAuthorizationController *authorizationController = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[appleIDRequest]];
//
authorizationController.delegate = self;
//
authorizationController.presentationContextProvider = self;
//
[authorizationController performRequests];
}
else{
//
NSLog(@"该系统版本不可用Apple登录");
NSDictionary *resultData = @{
@"code": @500,
@"msg" : @"该系统版本不可用Apple登录",
@"user" : @"",
@"familyName" : @"",
@"givenName" : @"",
@"email" : @"",
@"identityTokenStr": @"",
@"authorizationCodeStr": @""
};
[self resultData: resultData];
}
}
#pragma mark - delegate
//@optional
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0)){
// NSLog(@"授权完成:::%@", authorization.credential);
NSLog(@"授权完成---开始返回数据");
if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
// 使ASAuthorizationAppleIDCredential
ASAuthorizationAppleIDCredential *appleIDCredential = (ASAuthorizationAppleIDCredential *)authorization.credential;
NSString *user = appleIDCredential.user;
// 使
NSString *familyName = appleIDCredential.fullName.familyName;
NSString *givenName = appleIDCredential.fullName.givenName;
NSString *email = appleIDCredential.email;
NSData *identityToken = appleIDCredential.identityToken;
NSData *authorizationCode = appleIDCredential.authorizationCode;
// 使
NSString *identityTokenStr = [[NSString alloc] initWithData:identityToken encoding:NSUTF8StringEncoding];
NSString *authorizationCodeStr = [[NSString alloc] initWithData:authorizationCode encoding:NSUTF8StringEncoding];
// NSLog(@"后台参数--%@\n\n%@", identityTokenStr, authorizationCodeStr);
// NSLog(@"后台参数identityTokenStr---%@", identityTokenStr);
// NSLog(@"后台参数authorizationCodeStr---%@", authorizationCodeStr);
// Create an account in your system.
// For the purpose of this demo app, store the userIdentifier in the keychain.
// 使
// [YostarKeychain save:KEYCHAIN_IDENTIFIER(@"userIdentifier") data:user];
// NSLog(@"user--%@", user);
// NSLog(@"familyName--%@", familyName);
// NSLog(@"givenName--%@", givenName);
// NSLog(@"email--%@", email);
NSDictionary *resultData = @{
@"code": @200,
@"msg" : @"获取成功",
@"user" : user,
@"familyName" : familyName != nil ? familyName : @"",
@"givenName" : givenName != nil ? givenName : @"",
@"email" : email != nil ? email : @"",
@"identityTokenStr": identityTokenStr,
@"authorizationCodeStr": authorizationCodeStr
};
[self resultData: resultData];
}else if ([authorization.credential isKindOfClass:[ASPasswordCredential class]]){
// iCloudiOS 12
// Sign in using an existing iCloud Keychain credential.
// 使
ASPasswordCredential *passwordCredential = (ASPasswordCredential*)authorization.credential;
//
NSString *user = passwordCredential.user;
//
NSString *password = passwordCredential.password;
NSLog(@"user--%@", user);
NSLog(@"password--%@", password);
NSDictionary *resultData = @{
@"code": @200,
@"msg" : @"获取成功",
@"user" : user,
@"familyName" : @"",
@"givenName" : @"",
@"email" : @"",
@"identityTokenStr": @"",
@"authorizationCodeStr": @""
};
[self resultData: resultData];
}else{
NSLog(@"授权信息均不符");
NSDictionary *resultData = @{
@"code": @500,
@"msg" : @"授权信息均不符",
@"user" : @"",
@"familyName" : @"",
@"givenName" : @"",
@"email" : @"",
@"identityTokenStr": @"",
@"authorizationCodeStr": @""
};
[self resultData: resultData];
}
}
//
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error API_AVAILABLE(ios(13.0)){
// Handle error.
NSLog(@"苹果登录授权失败:%@", error);
NSString *errorMsg = nil;
switch (error.code) {
case ASAuthorizationErrorCanceled:
errorMsg = @"用户取消了授权请求";
break;
case ASAuthorizationErrorFailed:
errorMsg = @"授权请求失败";
break;
case ASAuthorizationErrorInvalidResponse:
errorMsg = @"授权请求响应无效";
break;
case ASAuthorizationErrorNotHandled:
errorMsg = @"未能处理授权请求";
break;
case ASAuthorizationErrorUnknown:
errorMsg = @"授权请求失败未知原因";
break;
default:
break;
}
NSLog(@"%@", errorMsg);
NSDictionary *resultData = @{
@"code": @500,
@"msg" : errorMsg,
@"user" : @"",
@"familyName" : @"",
@"givenName" : @"",
@"email" : @"",
@"identityTokenStr": @"",
@"authorizationCodeStr": @""
};
[self resultData: resultData];
}
#pragma mark - window
- (ASPresentationAnchor)presentationAnchorForAuthorizationController:(ASAuthorizationController *)controller API_AVAILABLE(ios(13.0)){
NSLog(@"88888888888");
// window
return [UIApplication sharedApplication].windows.lastObject;
}
#pragma mark -
- (UIViewController *)getRootViewController {
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
return window.rootViewController;
}
#pragma mark ======viewUIViewController========
- (UIViewController *)findCurrentViewController{
UIWindow *window = [[UIApplication sharedApplication].delegate window];
// UIViewController * vc = [[ViewController alloc] init];
// window.rootViewController = vc;
// UITapGestureRecognizer* singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(clickAllScreen:)];
// [window addGestureRecognizer:singleTap];
UIViewController *topViewController = [window rootViewController];
while (true) {
if (topViewController.presentedViewController) {
topViewController = topViewController.presentedViewController;
} else if ([topViewController isKindOfClass:[UINavigationController class]] && [(UINavigationController*)topViewController topViewController]) {
topViewController = [(UINavigationController *)topViewController topViewController];
} else if ([topViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController *tab = (UITabBarController *)topViewController;
topViewController = tab.selectedViewController;
} else {
break;
}
}
return topViewController;
}
- (void) clickAllScreen:(UITapGestureRecognizer *) recognizer {
NSLog(@"点击事件屏蔽");
}
@end

View File

@ -1,13 +0,0 @@
import Flutter
public class AliAuthPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "ali_auth", binaryMessenger: registrar.messenger())
let instance = AliAuthPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
result(FlutterMethodNotImplemented)
}
}

View File

@ -0,0 +1,17 @@
//
// PNSBaseNavigationController.h
// ATAuthSceneDemo
//
// Created by Yau的MacBook on 2022/5/19.
// Copyright © 2022 Yau的MacBook. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface PNSBaseNavigationController : UINavigationController
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,29 @@
//
// PNSBaseNavigationController.m
// ATAuthSceneDemo
//
// Created by YauMacBook on 2022/5/19.
// Copyright © 2022 YauMacBook. All rights reserved.
//
#import "PNSBaseNavigationController.h"
@interface PNSBaseNavigationController ()
@end
@implementation PNSBaseNavigationController
- (BOOL)shouldAutorotate {
return [[self.viewControllers lastObject] shouldAutorotate];
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}
//- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
// return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
//}
@end

View File

@ -0,0 +1,37 @@
//
// PNSBaseViewController.h
// ATAuthSceneDemo
//
// Created by Yau的MacBook on 2022/5/19.
// Copyright © 2022 Yau的MacBook. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface PNSBaseViewController : UIViewController
/**
* controller里面的viewself.view的subViewview初始化的相关代码都写在这里
*
* @warning initSubviews只负责subviews的init <b>viewDidLayoutSubviews</b>
*/
- (void)initSubviews NS_REQUIRES_SUPER;
/**
* controller里面的viewself.view的subViewview初始化的相关代码都写在这里
*
* @warning setLayoutSubviews只负责布局subviews的约束
*/
- (void)setLayoutSubviews;
/// 是否需要将状态栏改为浅色文字,默认为浅文字色
- (BOOL)shouldSetStatusBarStyleLight;
/// 是否影藏电池栏 (默认不影藏)
- (BOOL)shouldHiddenStatusBar;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,77 @@
//
// PNSBaseViewController.m
// ATAuthSceneDemo
//
// Created by YauMacBook on 2022/5/19.
// Copyright © 2022 YauMacBook. All rights reserved.
//
#import "PNSBaseViewController.h"
@interface PNSBaseViewController ()
@end
@implementation PNSBaseViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
[self initSubviews];
[self setLayoutSubviews];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
#pragma mark -
- (BOOL)prefersStatusBarHidden {
return NO;
}
- (UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleDefault;
}
- (BOOL)shouldSetStatusBarStyleLight {
return YES;
}
- (BOOL)shouldHiddenStatusBar {
return NO;
}
#pragma mark - UI
- (void)initSubviews {
//
}
- (void)setLayoutSubviews {
//
}
#pragma mark - , , APP
//
- (BOOL)shouldAutorotate {
return YES;
}
//
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
NSLog(@"[%@,%@]===已被释放",NSStringFromClass([self class]), self.navigationItem.title ?: self.title);
}
@end

View File

@ -0,0 +1,21 @@
//
// NSDictionaryUtils.h
// UZEngine
//
// Created by Yau的MacBook on 2022/5/19.
// Copyright © 2022 Yau的MacBook. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface NSDictionary (Utils)
- (NSInteger)integerValueForKey:(NSString *)key defaultValue:(NSInteger)defaultValue;
- (int)intValueForKey:(NSString *)key defaultValue:(int)defaultValue;
- (long long)longlongValueForKey:(NSString *)key defaultValue:(long long)defaultValue;
- (float)floatValueForKey:(NSString *)key defaultValue:(float)defaultValue;
- (BOOL)boolValueForKey:(NSString *)key defaultValue:(BOOL)defaultValue;
- (NSString *)stringValueForKey:(NSString *)key defaultValue:(NSString *)defaultValue;
- (NSArray *)arrayValueForKey:(NSString *)key defaultValue:(NSArray *)defaultValue;
- (NSDictionary *)dictValueForKey:(NSString *)key defaultValue:(NSDictionary *)defaultValue;
@end

View File

@ -0,0 +1,124 @@
//
// NSDictionary+Utils.m
// BCPay
//
// Created by YauMacBook on 2022/5/19.
// Copyright © 2022 YauMacBook. All rights reserved.
//
#import "NSDictionary+Utils.h"
@implementation NSDictionary (Utils)
/**
* @brief akey@"" (nil使)
*
* @param aKey key
*
* @return value
*/
/**
* key
*
* @param key
*
* @return valuenilnull0
*/
- (NSInteger)integerValueForKey:(NSString*)key defaultValue:(NSInteger)defaultValue {
if ([self valueForKeyIsNumber:key]) {
return [[self valueForKey:key] integerValue];
}
return defaultValue;
}
- (int)intValueForKey:(NSString *)key defaultValue:(int)defaultValue{
if ([self valueForKeyIsNumber:key]) {
return [[self valueForKey:key] intValue];
}
return defaultValue;
}
- (long long)longlongValueForKey:(NSString*)key defaultValue:(long long)defaultValue {
if ([self valueForKeyIsNumber:key]) {
return [[self valueForKey:key] longLongValue];
}
return defaultValue;
}
- (float)floatValueForKey:(NSString*)key defaultValue:(float)defaultValue {
if ([self valueForKeyIsNumber:key]) {
return [[self valueForKey:key] floatValue];
}
return defaultValue;
}
- (BOOL)boolValueForKey:(NSString*)key defaultValue:(BOOL)defaultValue {
if ([self valueForKeyIsNumber:key]) {
return [[self valueForKey:key] boolValue];
}
return defaultValue;
}
- (NSString *)stringValueForKey:(NSString*)key defaultValue:(NSString*)defaultValue {
if ([self valueForKeyIsString:key]) {
return [self valueForKey:key];
}
return defaultValue;
}
- (NSArray *)arrayValueForKey:(NSString *)key defaultValue:(NSArray *)defaultValue {
if ([self valueForKeyIsArray:key]) {
return [self valueForKey:key];
}
return defaultValue;
}
- (NSDictionary *)dictValueForKey:(NSString *)key defaultValue:(NSDictionary *)defaultValue {
if ([self valueForKeyIsNSDictionary:key]) {
return [self valueForKey:key];
}
return defaultValue;
}
///**
// * @brief &nbsp;
// *
// * @param aKey key
// *
// * @return value
// */
//
//- (NSString *)replaceNBSPforKey:(id)aKey {
// NSString *value = [self objectForKey:aKey];
//
// if (!value) {
// value = @"";
// }
// NSString* str = [value stringByReplacingOccurrencesOfString:@"&nbsp;" withString:@" "] ;
//
// return [NSString stringWithFormat:@"%@",str];
//}
- (BOOL)valueForKeyIsArray:(NSString *)key {
return [self valueForKeyIsType:key type:[NSArray class]];
}
- (BOOL)valueForKeyIsString:(NSString *)key {
return [self valueForKeyIsType:key type:[NSString class]];
}
- (BOOL)valueForKeyIsNumber:(NSString *)key {
return [self valueForKeyIsType:key type:[NSNumber class]];
}
- (BOOL)valueForKeyIsNSDictionary:(NSString *)key {
return [self valueForKeyIsType:key type:[NSDictionary class]];
}
- (BOOL)valueForKeyIsType:(NSString *)key type:(Class)kClass {
id value = [self objectForKey:key];
if (value == nil || [value isKindOfClass:[NSNull class]] || ![value isKindOfClass:kClass]) {
return NO;
}
return YES;
}
@end

View File

@ -0,0 +1,22 @@
//
// PrivacyWebViewController.h
// ATAuthSceneDemo
//
// Created by Yau的MacBook on 2022/5/19.
// Copyright © 2022 Yau的MacBook. All rights reserved.
//
#import "PNSBaseViewController.h"
NS_ASSUME_NONNULL_BEGIN
@interface PrivacyWebViewController : PNSBaseViewController
- (instancetype)initWithUrl:(NSString *)url andUrlName:(NSString *)urlName;
/// 是否隐藏系统的导航栏
@property (nonatomic, assign) BOOL isHiddenNavgationBar;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,85 @@
//
// PrivacyWebViewController.m
// ATAuthSceneDemo
//
// Created by YauMacBook on 2022/5/19.
// Copyright © 2022 YauMacBook. All rights reserved.
//
#import "PrivacyWebViewController.h"
#import <WebKit/WebKit.h>
@interface PrivacyWebViewController ()<WKNavigationDelegate,WKUIDelegate>
@property (nonatomic, strong) WKWebView *webView;
@property (nonatomic, strong) NSString *url;
@property (nonatomic, copy) NSString *urlName;
@end
@implementation PrivacyWebViewController
- (instancetype)initWithUrl:(NSString *)url andUrlName:(nonnull NSString *)urlName{
self = [super init];
if (self) {
_url = url ?: nil;
_urlName = urlName ?: nil;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = self.urlName ?: @"服务协议";
[self.view addSubview:self.webView];
if (self.url) {
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:self.url]]];
}
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (!self.isHiddenNavgationBar) {
//
[self.navigationController setNavigationBarHidden:NO animated:YES];
}
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (self.isHiddenNavgationBar) {
//
[self.navigationController setNavigationBarHidden:YES animated:YES];
}
}
#pragma mark - UI
- (WKWebView *)webView {
if (!_webView) {
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
WKPreferences *preference = [[WKPreferences alloc]init];
preference.minimumFontSize = 0;
preference.javaScriptEnabled = YES;
preference.javaScriptCanOpenWindowsAutomatically = YES;
config.preferences = preference;
float y = self.navigationController.navigationBar.frame.size.height + [UIApplication sharedApplication].statusBarFrame.size.height;
_webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, y, self.view.frame.size.width, self.view.frame.size.height) configuration:config];
// ,
_webView.allowsBackForwardNavigationGestures = YES;
_webView.navigationDelegate = self;
_webView.UIDelegate = self;
}
return _webView;
}
- (void)initSubviews {
[super initSubviews];
[self.view addSubview:self.webView];
}
@end

View File

@ -0,0 +1,5 @@
#import <UIKit/UIKit.h>
@interface CustomButton : UIButton
@end

View File

@ -0,0 +1,15 @@
#import "CustomButton.h"
@implementation CustomButton
// title
- (CGRect)titleRectForContentRect:(CGRect)contentRect {
/// CGFloat x, CGFloat y, CGFloat width, CGFloat height
return CGRectMake(0, self.bounds.size.height + 5, self.bounds.size.width, 16);
}
//
- (CGRect)backgroundRectForBounds:(CGRect)bounds{
return CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height);
}
@end

View File

@ -0,0 +1,22 @@
//
// PNSBuildModelUtils.h
// ATAuthSceneDemo
//
// Created by Yau的MacBook on 2022/5/19.
// Copyright © 2022 Yau的MacBook. All rights reserved.
//
#import <ATAuthSDK/ATAuthSDK.h>
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface PNSBuildModelUtils : NSObject
+ (TXCustomModel *)buildModelWithStyle:(NSDictionary *)dict
target:(id)target
selector:(SEL)selector;
@end
NS_ASSUME_NONNULL_END

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,20 @@
//
// UIColor+Hex.h
// Pods
//
// Created by Yau on 2023/4/13.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#ifndef UIColor_Hex_h
#define UIColor_Hex_h
@interface UIColor (Hex)
+ (UIColor*)colorWithHex:(NSString *)hex defaultValue:(NSString *)defaultValue;
+ (UIColor*)colorWithHexString:(NSString *)hex alpha: (CGFloat)opacity defaultValue:(UIColor *)defaultValue;
+ (UIColor*)colorWithAlphaHex:(NSInteger)hex alpha: (CGFloat)opacity defaultValue:(UIColor *)defaultValue;
@end
#endif /* UIColor_Hex_h */

View File

@ -0,0 +1,83 @@
//
// UIColor+Hex.m
// ali_auth
//
// Created by Yau on 2023/4/13.
//
#import "UIColor+Hex.h"
@implementation UIColor (Hex)
+ (UIColor*)colorWithHex:(NSString*)hexColor defaultValue:(NSString*)defaultValue {
if (
hexColor == nil || [hexColor isEqual: @""]
) {
hexColor = defaultValue;
}
if (hexColor.length < 8) {
return [self colorWithHexString: hexColor alpha: 1 defaultValue: [UIColor blueColor]];
}
unsigned int alpha, red, green, blue;
NSRange range;
range.length =2;
range.location =1;
[[NSScanner scannerWithString:[hexColor substringWithRange:range]]scanHexInt:&alpha];//
range.location =3;
[[NSScanner scannerWithString:[hexColor substringWithRange:range]]scanHexInt:&red];
range.location =5;
[[NSScanner scannerWithString:[hexColor substringWithRange:range]]scanHexInt:&green];
range.location =7;
[[NSScanner scannerWithString:[hexColor substringWithRange:range]]scanHexInt:&blue];
return [UIColor colorWithRed:(float)(red/255.0f)green:(float)(green/255.0f)blue:(float)(blue/255.0f)alpha:(float)(alpha/255.0f)];
}
/**
16UIColor
@param hexColor 160x#616
@param opacity
@return 16
*/
+(UIColor *)colorWithHexString:(NSString *)hexColor alpha:(CGFloat)opacity defaultValue:(UIColor*)defaultValue{
NSString * cString = [[hexColor stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString];
// String should be 6 or 8 characters
if ([cString length] < 6) return [UIColor blackColor];
// strip 0X if it appears
if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2];
if ([cString hasPrefix:@"#"]) cString = [cString substringFromIndex:1];
if ([cString length] != 6) return [UIColor blackColor];
// Separate into r, g, b substrings
NSRange range;
range.location = 0;
range.length = 2;
NSString * rString = [cString substringWithRange:range];
range.location = 2;
NSString * gString = [cString substringWithRange:range];
range.location = 4;
NSString * bString = [cString substringWithRange:range];
// Scan values
unsigned int r, g, b;
[[NSScanner scannerWithString:rString] scanHexInt:&r];
[[NSScanner scannerWithString:gString] scanHexInt:&g];
[[NSScanner scannerWithString:bString] scanHexInt:&b];
return [UIColor colorWithRed:((float)r / 255.0f)
green:((float)g / 255.0f)
blue:((float)b / 255.0f)
alpha:opacity];
}
+ (UIColor *)colorWithAlphaHex:(NSInteger)hex alpha:(CGFloat)alpha defaultValue:(UIColor*)defaultValue{
return [UIColor colorWithRed:((float)((hex & 0xFF0000) >> 16))/255.0 green:((float)((hex & 0xFF00) >> 8))/255.0 blue:((float)(hex & 0xFF))/255.0 alpha:alpha];
}
@end

View File

@ -0,0 +1,16 @@
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface PNSBackgroundView : UIView
@property (nonatomic, strong) NSURL *gifUrl;
@property (nonatomic, strong) NSURL *videoUrl;
- (void)show;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,73 @@
#import "PNSBackgroundView.h"
#import <AVFoundation/AVFoundation.h>
#import "UIImageView+WebCache.h"
@interface PNSBackgroundView ()
@property (nonatomic, strong) UIImageView *imgView;
@property (nonatomic, strong) AVPlayerLayer *playerLayer;
@end
@implementation PNSBackgroundView
- (void)show {
// GIF
self.imgView = [self buildGIFViewWithUrl:self.gifUrl color:UIColor.blackColor];
if (self.imgView) {
[self addSubview:self.imgView];
}
// video
self.playerLayer = [self buildVideoViewWithUrl:self.videoUrl color:UIColor.blackColor];
if (self.playerLayer) {
// session
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];
[self.layer addSublayer:self.playerLayer];
[self.playerLayer.player play]; //
//
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(playbackFinished:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:self.playerLayer.player.currentItem];
}
}
- (void)playbackFinished:(NSNotification *)notification {
[self.playerLayer.player seekToTime:CMTimeMake(0, 1)];
[self.playerLayer.player play];
}
- (void)layoutSubviews {
[super layoutSubviews];
self.playerLayer.frame = self.bounds;
self.imgView.frame = self.bounds;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (UIImageView *)buildGIFViewWithUrl:(NSURL *)url color:(UIColor *)color {
if (url == nil) { return nil; }
UIImageView *view = [[UIImageView alloc] init];
view.contentMode = UIViewContentModeScaleAspectFill;
[view sd_setImageWithURL:url];
if (color) {
view.backgroundColor = color;
}
return view;
}
- (AVPlayerLayer *)buildVideoViewWithUrl:(NSURL *)url color:(UIColor *)color {
if (url == nil) { return nil; }
AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithURL:url];
AVPlayer *player = [[AVPlayer alloc] initWithPlayerItem:playerItem];
player.muted = YES;
AVPlayerLayer *playLayer = [AVPlayerLayer playerLayerWithPlayer:player];
playLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
if (color) {
playLayer.backgroundColor = color.CGColor;
}
return playLayer;
}
@end

View File

@ -1,13 +1,42 @@
#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
#
Pod::Spec.new do |s|
s.name = 'ali_auth'
s.version = '1.3.7'
s.summary = 'Alibaba Cloud phone auth plugin for Flutter.'
s.homepage = 'https://github.com/CodeGather/flutter_ali_auth'
s.license = { :type => 'MIT' }
s.author = { 'sean' => 'author@example.com' }
s.source = { :http => 'https://github.com/CodeGather/flutter_ali_auth' }
s.source_files = 'Classes/**/*'
s.summary = 'A new flutter plugin project.'
s.description = <<-DESC
是一个集成阿里云号码认证服务SDK的flutter插件
DESC
s.homepage = 'http://ki5k.com'
s.license = { :file => '../LICENSE' }
s.author = { 'Your Company' => 'raohong07@163.com' }
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.public_header_files = 'Classes/**/*.h'
s.dependency 'Flutter'
s.platform = :ios, '13.0'
s.swift_version = '5.0'
s.dependency 'SDWebImage'
s.dependency 'MJExtension'
# s.dependency 'MBProgressHUD'
s.frameworks = 'Network'
s.vendored_frameworks = 'libs/ATAuthSDK.framework', 'libs/YTXMonitor.framework', 'libs/YTXOperators.framework'
s.static_framework = false
# 解决移动crash
s.xcconfig = {
'OTHER_LDFLAGS' => '-ObjC',
'ENABLE_BITCODE' => 'NO'
}
# 加载静态资源
s.resources = ['Assets/*']
s.ios.deployment_target = '11.0'
# s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' }
s.pod_target_xcconfig = {'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64' }
s.user_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64' }
end

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