Repository: finogeeks/finclip-android-demo
Branch: master
Commit: 2ae719e03e73
Files: 53
Total size: 85.8 KB
Directory structure:
gitextract_95_p49xo/
├── .github/
│ └── workflows/
│ ├── issue.yml
│ └── pull_request.yml
├── .gitignore
├── .idea/
│ ├── .name
│ ├── codeStyles/
│ │ └── Project.xml
│ ├── compiler.xml
│ ├── deploymentTargetDropDown.xml
│ ├── deploymentTargetSelector.xml
│ ├── gradle.xml
│ ├── jarRepositories.xml
│ ├── kotlinc.xml
│ ├── migrations.xml
│ ├── misc.xml
│ ├── runConfigurations.xml
│ └── vcs.xml
├── README.md
├── app/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ ├── release/
│ │ └── app-release.apk
│ └── src/
│ ├── androidTest/
│ │ └── java/
│ │ └── com/
│ │ └── finogeeks/
│ │ └── mop/
│ │ └── demo/
│ │ └── ExampleInstrumentedTest.java
│ ├── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── finogeeks/
│ │ │ └── mop/
│ │ │ └── demo/
│ │ │ ├── AppletHandler.java
│ │ │ ├── InputContentActivity.java
│ │ │ ├── MainActivity.java
│ │ │ ├── MopApplication.java
│ │ │ ├── ScanQRCodeActivity.kt
│ │ │ ├── ScanStartAppletActivity.kt
│ │ │ └── customapi/
│ │ │ ├── CustomApi.java
│ │ │ ├── CustomH5Api.java
│ │ │ └── user/
│ │ │ ├── LoginApi.java
│ │ │ └── ProfileApi.java
│ │ └── res/
│ │ ├── drawable/
│ │ │ └── ic_launcher_background.xml
│ │ ├── drawable-v24/
│ │ │ └── ic_launcher_foreground.xml
│ │ ├── layout/
│ │ │ ├── activity_input_content.xml
│ │ │ ├── activity_main.xml
│ │ │ ├── activity_scan_qr_code.xml
│ │ │ └── activity_scan_start_applet.xml
│ │ ├── mipmap-anydpi-v26/
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ └── values/
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test/
│ └── java/
│ └── com/
│ └── finogeeks/
│ └── mop/
│ └── demo/
│ └── ExampleUnitTest.java
├── build.gradle
├── finclip.jks
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/issue.yml
================================================
name: Notify
on:
issues:
types: [opened]
issue_comment:
types: [created]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Notify
run: curl --location --request POST 'https://api.finogeeks.club/api/v1/finstore/webhooks/61b331d79b3dad0001f72fa2/postreceive?nonce=jhd2QyrArsc' --header "Content-Type:application/json" --data-raw '{"msg":"仓库 ${{github.repository}} 有新的 issue"}'
================================================
FILE: .github/workflows/pull_request.yml
================================================
name: Notify
on:
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Notify
run: curl --location --request POST 'https://api.finogeeks.club/api/v1/finstore/webhooks/61b331d79b3dad0001f72fa2/postreceive?nonce=jhd2QyrArsc' --header "Content-Type:application/json" --data-raw '{"msg":"仓库 ${{github.repository}} 有新的 PR ${{ github.event.pull_request._links.html.href }}"}'
================================================
FILE: .gitignore
================================================
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
================================================
FILE: .idea/.name
================================================
mopdemo
================================================
FILE: .idea/codeStyles/Project.xml
================================================
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<codeStyleSettings language="XML">
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
</code_scheme>
</component>
================================================
FILE: .idea/compiler.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="11" />
</component>
</project>
================================================
FILE: .idea/deploymentTargetDropDown.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<runningDeviceTargetSelectedWithDropDown>
<Target>
<type value="RUNNING_DEVICE_TARGET" />
<deviceKey>
<Key>
<type value="SERIAL_NUMBER" />
<value value="FA7AZ1A07148" />
</Key>
</deviceKey>
</Target>
</runningDeviceTargetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2022-10-24T09:17:42.427931Z" />
</component>
</project>
================================================
FILE: .idea/deploymentTargetSelector.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetSelector">
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
</selectionStates>
</component>
</project>
================================================
FILE: .idea/gradle.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="CHOOSE_PER_TEST" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveExternalAnnotations" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>
================================================
FILE: .idea/jarRepositories.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="maven" />
<option name="name" value="maven" />
<option name="url" value="https://gradle.finogeeks.club/repository/applet/" />
</remote-repository>
<remote-repository>
<option name="id" value="BintrayJCenter" />
<option name="name" value="BintrayJCenter" />
<option name="url" value="https://jcenter.bintray.com/" />
</remote-repository>
<remote-repository>
<option name="id" value="Google" />
<option name="name" value="Google" />
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
</remote-repository>
</component>
</project>
================================================
FILE: .idea/kotlinc.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.7.22" />
</component>
</project>
================================================
FILE: .idea/migrations.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>
================================================
FILE: .idea/misc.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeSettings">
<configurations>
<configuration PROFILE_NAME="Debug" CONFIG_NAME="Debug" />
</configurations>
</component>
<component name="DesignSurface">
<option name="filePathToZoomLevelMap">
<map>
<entry key="app/src/main/res/layout/activity_main.xml" value="0.34427083333333336" />
<entry key="app/src/main/res/layout/activity_scan_qr_code.xml" value="0.12135416666666667" />
<entry key="app/src/main/res/layout/activity_scan_start_applet.xml" value="0.20244565217391305" />
</map>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="corretto-11" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>
================================================
FILE: .idea/runConfigurations.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
<option value="com.intellij.execution.junit.PatternConfigurationProducer" />
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
<option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
</set>
</option>
</component>
</project>
================================================
FILE: .idea/vcs.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
================================================
FILE: README.md
================================================
<p align="center">
<a href="https://www.finclip.com?from=github">
<img width="auto" src="https://www.finclip.com/mop/document/images/logo.png">
</a>
</p>
<p align="center">
<strong>FinClip Android DEMO</strong></br>
<p>
<p align="center">
本项目提供在 Android 环境中运行小程序的 DEMO 样例
<p>
<p align="center">
👉 <a href="https://www.finclip.com?from=github">https://www.finclip.com/</a> 👈
</p>
<div align="center">
<a href="#"><img src="https://img.shields.io/badge/%E4%B8%93%E5%B1%9E%E5%BC%80%E5%8F%91%E8%80%85-20000%2B-brightgreen"></a>
<a href="#"><img src="https://img.shields.io/badge/%E5%B7%B2%E4%B8%8A%E6%9E%B6%E5%B0%8F%E7%A8%8B%E5%BA%8F-6000%2B-blue"></a>
<a href="#"><img src="https://img.shields.io/badge/%E5%B7%B2%E9%9B%86%E6%88%90%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%BA%94%E7%94%A8-75%2B-yellow"></a>
<a href="#"><img src="https://img.shields.io/badge/%E5%AE%9E%E9%99%85%E8%A6%86%E7%9B%96%E7%94%A8%E6%88%B7-2500%20%E4%B8%87%2B-orange"></a>
<a href="https://www.zhihu.com/org/finchat"><img src="https://img.shields.io/badge/FinClip--lightgrey?logo=zhihu&style=social"></a>
<a href="https://www.finclip.com/blog/"><img src="https://img.shields.io/badge/FinClip%20Blog--lightgrey?logo=ghost&style=social"></a>
</div>
<p align="center">
<div align="center">
[官方网站](https://www.finclip.com/) | [示例小程序](https://www.finclip.com/#/market) | [开发文档](https://www.finclip.com/mop/document/) | [部署指南](https://www.finclip.com/mop/document/introduce/quickStart/cloud-server-deployment-guide.html) | [SDK 集成指南](https://www.finclip.com/mop/document/introduce/quickStart/intergration-guide.html) | [API 列表](https://www.finclip.com/mop/document/develop/api/overview.html) | [组件列表](https://www.finclip.com/mop/document/develop/component/overview.html) | [隐私承诺](https://www.finclip.com/mop/document/operate/safety.html)
</div>
-----
## 🤔 FinClip 是什么?
有没有**想过**,开发好的微信小程序能放在自己的 APP 里直接运行,只需要开发一次小程序,就能在不同的应用中打开它,是不是很不可思议?
有没有**试过**,在自己的 APP 中引入一个 SDK ,应用中不仅可以打开小程序,还能自定义小程序接口,修改小程序样式,是不是觉得更不可思议?
这就是 FinClip ,就是有这么多不可思议!
## ⚙️ 操作步骤
### 第一步 配置 build.gradle 文件
在工程的 `build.gradle` 中添加 maven 仓库的地址:
```bash
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle:3.5.2"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.60"
}
}
allprojects {
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }
maven {
url "https://gradle.finogeeks.club/repository/applet/"
credentials {
username "applet"
password "123321"
}
}
}
}
```
### 第二步 在 gradle 中依赖 SDK
`implementation 'com.finogeeks.lib:finapplet:+'`
### 第三步 配置混淆规则
集成 SDK 之后,为了避免 SDK 中部分不能被混淆的代码被混淆,需要在工程的混淆规则配置文件中增加以下配置:
``-keep class com.finogeeks.** {*;}``
### 第四步 SDK初始化
我们强烈建议在 `Application` 中对SDK进行初始化,初始化 SDK 需要传入的各项参数如下:
```java
FinAppConfig config = new FinAppConfig.Builder()
.setAppKey("SDKKEY")
.setAppSecret("SECRET")
.setApiUrl("https://api.finclip.com")
.setApiPrefix("/api/v1/mop/")
.setGlideWithJWT(false)
.build();
FinCallback<Object> callback = new FinCallback<Object>() {
@Override
public void onSuccess(Object result) {
// SDK初始化成功
}
@Override
public void onError(int code, String error) {
// SDK初始化失败
Toast.makeText(AppletApplication.this, "SDK初始化失败", Toast.LENGTH_SHORT).show();
}
@Override
public void onProgress(int status, String error) {
}
};
FinAppClient.INSTANCE.init(this, config, callback);
```
SDK 采用多进程机制实现,每个小程序运行在独立的进程中,即一个小程序对应一个进程。在初始化SDK时,要特别注意的一点是:**小程序进程在创建的时候,不需要执行任何初始化操作,即使是小程序SDK的初始化,也不需要在小程序进程中执行。**
> 举个例子🌰<br>
应用使用了一些第三方库,这些库需要在应用启动时先初始化,那么在 Application 中执行初始化时,只有当前进程为宿主进程时才需要初始化这些第三方库,小程序进程是不需要初始化这些库的。<br>
因此,在初始化SDK之前,一定要判断当前进程是哪一个进程,如果是小程序进程,就不进行任何操作了:
```java
if (FinAppClient.INSTANCE.isFinAppProcess(this)) {
return;
}
```
### 第五步 打开小程序
```java
FinAppClient.INSTANCE.getAppletApiManager().startApplet(this, "appid");
```
- **SDK KEY** 和 **SDK SECRET** 可以从 [FinClip](https://finclip.com/#/home) 获取,点 [这里](https://finclip.com/#/register) 注册账号;
- 进入平台后,在「应用管理」页面添加你自己的包名后,点击「复制」即可获得 key\secret\apisever 字段;
- **apiServer** 和 **apiPrefix** 是固定字段,请直接参考本 DEMO ;
- **小程序 ID** 是管理后台上架的小程序 APP ID,需要在「小程序管理」中创建并在「应用管理」中关联;
> 小程序 ID 与 微信小程序ID 不一样哦!(这里是特指 FinClip 平台的 ID )
## 📋 集成文档
[点击这里](https://www.finclip.com/mop/document/introduce/quickStart/intergration-guide.html#_2-android-%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90) 查看 Android 快速集成文档
## 📘 目录结构
```
.
├─.github
│
├─.idea 由IDE自动生成,无需关注
│
├─app 项目源码主目录
│ │
│ │ build.gradle 应用构建配置
│ │
│ │ proguard-rules.pro 混淆配置
│ │
│ ├─release 构建应用生成的apk目录
│ │
│ └─src
│ ├─androidTest 单元测试目录,由IDE自动生成,无需关注
│ │
│ ├─main 应用源码主目录
│ │ │ AndroidManifest.xml 应用清单文件
│ │ │
│ │ ├─java 应用源码目录
│ │ │
│ │ └─res 资源文件目录
│ │ ├─drawable darwable资源目录
│ │ │
│ │ ├─drawable-v24 darwable资源目录
│ │ │
│ │ ├─layout 布局文件目录
│ │ │
│ │ ├─mipmap-anydpi-v26 图片资源目录
│ │ │
│ │ ├─mipmap-hdpi 图片资源目录
│ │ │
│ │ ├─mipmap-mdpi 图片资源目录
│ │ │
│ │ ├─mipmap-xhdpi 图片资源目录
│ │ │
│ │ ├─mipmap-xxhdpi 图片资源目录
│ │ │
│ │ ├─mipmap-xxxhdpi 图片资源目录
│ │ │
│ │ └─values 各项资源值配置目录
│ │
│ └─test 单元测试目录,由IDE自动生成,无需关注
│
└─gradle gradle版本配置目录,一般情况下无需关注
```
## 🔗 常用链接
以下内容是您在 FinClip 进行开发与体验时,常见的问题与指引信息
- [FinClip 官网](https://www.finclip.com/#/home)
- [示例小程序](https://www.finclip.com/#/market)
- [文档中心](https://www.finclip.com/mop/document/)
- [SDK 部署指南](https://www.finclip.com/mop/document/introduce/quickStart/intergration-guide.html)
- [小程序代码结构](https://www.finclip.com/mop/document/develop/guide/structure.html)
- [iOS 集成指引](https://www.finclip.com/mop/document/runtime-sdk/ios/ios-integrate.html)
- [Android 集成指引](https://www.finclip.com/mop/document/runtime-sdk/android/android-integrate.html)
- [Flutter 集成指引](https://www.finclip.com/mop/document/runtime-sdk/flutter/flutter-integrate.html)
## ☎️ 联系我们
微信扫描下面二维码,关注官方公众号 **「凡泰极客」**,获取更多精彩内容。<br>
<img width="150px" src="https://www.finclip.com/mop/document/images/ic_qr.svg">
微信扫描下面二维码,加入官方微信交流群,获取更多精彩内容。<br>
<img width="150px" src="https://www-cdn.finclip.com/images/qrcode/qrcode_shequn_text.png">
## Stargazers
[](https://github.com/finogeeks/finclip-android-demo/stargazers)
## Forkers
[](https://github.com/finogeeks/finclip-android-demo/network/members)
================================================
FILE: app/.gitignore
================================================
/build
================================================
FILE: app/build.gradle
================================================
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.finogeeks.finclip.demo"
minSdkVersion 19
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
buildConfigField "String", "APP_KEY", "\"22LyZEib0gLTQdU3MUauATBwgfnTCJjdr7FCnywmAEM=\""
// App Secret
buildConfigField "String", "APP_SECRET", "\"bdfd76cae24d4313\""
// API服务地址
buildConfigField "String", "API_URL", "\"https://api.finclip.com\""
// API服务前缀
buildConfigField "String", "API_PREFIX", "\"/api/v1/mop/\""
ndk {
abiFilters "x86", "armeabi", 'armeabi-v7a', 'arm64-v8a'
}
}
signingConfigs {
debug {
keyAlias "FinClipDemo"
keyPassword "fino123456"
storeFile file("../finclip.jks")
storePassword "fino123456"
}
release {
keyAlias "FinClipDemo"
keyPassword "fino123456"
storeFile file("../finclip.jks")
storePassword "fino123456"
}
}
buildTypes {
debug {
minifyEnabled false
signingConfig signingConfigs.debug
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
release {
minifyEnabled true
signingConfig signingConfigs.release
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
packagingOptions {
// libsdkcore.so是被加固过的,不能被压缩,否则加载动态库时会报错
doNotStrip "*/x86/libsdkcore.so"
doNotStrip "*/x86_64/libsdkcore.so"
doNotStrip "*/armeabi/libsdkcore.so"
doNotStrip "*/armeabi-v7a/libsdkcore.so"
doNotStrip "*/arm64-v8a/libsdkcore.so"
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0'
implementation 'com.google.android.material:material:1.2.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'com.finogeeks.lib:finapplet:2.49.11'
implementation 'cn.bingoogolapple:bga-qrcode-zbar:1.3.7'
}
================================================
FILE: app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-keep class com.finogeeks.** {*;}
================================================
FILE: app/src/androidTest/java/com/finogeeks/mop/demo/ExampleInstrumentedTest.java
================================================
package com.finogeeks.mop.demo;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.finogeeks.mop.demo", appContext.getPackageName());
}
}
================================================
FILE: app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.finogeeks.mop.demo">
<uses-permission android:name="android.permission.VIBRATE" />
<application
android:name=".MopApplication"
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".InputContentActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar" />
<activity
android:name=".ScanStartAppletActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
android:label="@string/scan_start_applet" />
<activity
android:name=".ScanQRCodeActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/scan_start_applet"
android:screenOrientation="portrait" />
</application>
</manifest>
================================================
FILE: app/src/main/java/com/finogeeks/mop/demo/AppletHandler.java
================================================
package com.finogeeks.mop.demo;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.widget.Toast;
import androidx.annotation.NonNull;
import com.finogeeks.lib.applet.page.view.moremenu.MoreMenuItem;
import com.finogeeks.lib.applet.page.view.moremenu.MoreMenuType;
import com.finogeeks.lib.applet.rest.model.GrayAppletVersionConfig;
import com.finogeeks.lib.applet.sdk.api.IAppletHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* {@link IAppletHandler}实现类,用于实现一些业务场景,例如注册"更多"菜单项,转发小程序等。
*/
public class AppletHandler implements IAppletHandler {
@NonNull
private Context mContext;
private AppletHandler() {
}
public AppletHandler(@NonNull Context context) {
this.mContext = context;
}
/**
* 获取灰度发布配置参数
*
* @param appId 小程序ID
* @return 灰度发布配置参数
*/
@Nullable
@Override
public List<GrayAppletVersionConfig> getGrayAppletVersionConfigs(@NotNull String appId) {
return null;
}
/**
* 获取注册的"更多"菜单项
*
* @param appId 小程序ID
* @return 注册的"更多"菜单项
*/
@Nullable
@Override
public List<MoreMenuItem> getRegisteredMoreMenuItems(@NotNull String appId) {
List<MoreMenuItem> items = new ArrayList<>();
MoreMenuItem item0 = new MoreMenuItem("WXShareAPPFriends", "微信好朋友", MoreMenuType.ON_MINI_PROGRAM);
items.add(item0);
MoreMenuItem item1 = new MoreMenuItem("WXShareAPPMoments", "微信朋友圈", MoreMenuType.ON_MINI_PROGRAM, true);
items.add(item1);
MoreMenuItem item2 = new MoreMenuItem("ShareSinaWeibo", "新浪微博", MoreMenuType.ON_MINI_PROGRAM);
items.add(item2);
MoreMenuItem item3 = new MoreMenuItem("ShareQQFirends", "QQ", MoreMenuType.ON_MINI_PROGRAM);
items.add(item3);
MoreMenuItem item4 = new MoreMenuItem("ShareDingDing", "Dingding", MoreMenuType.ON_MINI_PROGRAM);
items.add(item4);
MoreMenuItem item5 = new MoreMenuItem("ShareLinks", "标题以后端配置为准", MoreMenuType.ON_MINI_PROGRAM);
items.add(item5);
MoreMenuItem item6 = new MoreMenuItem("SharePicture", "SharePicture", MoreMenuType.ON_MINI_PROGRAM);
items.add(item6);
MoreMenuItem item7 = new MoreMenuItem("Restart", "Restart", MoreMenuType.COMMON);
items.add(item7);
MoreMenuItem item8 = new MoreMenuItem("Desktop", "Desktop", MoreMenuType.COMMON);
items.add(item8);
return items;
}
/**
* 获取用户信息
*
* @return 用户信息[Map]
*/
@Nullable
@Override
public Map<String, String> getUserInfo() {
return null;
}
/**
* 小程序导航栏中的"关闭"按钮被点击
*
* @param appId 小程序ID
*/
@Override
public void onNavigationBarCloseButtonClicked(@NotNull String appId) {
Toast.makeText(mContext, "点击了小程序 " + appId + " 的导航栏关闭按钮", Toast.LENGTH_SHORT).show();
}
/**
* 注册的"更多"菜单项被点击
*
* @param appId 小程序ID
* @param path 小程序页面路径
* @param menuItemId 被点击的菜单条目的ID
* @param appInfo 小程序信息,是一串json,包含了小程序id、小程序名称、小程序图标、用户id、转发的数据内容等信息。
* [appInfo]的内容格式如下:
* {
* "appTitle": "凡泰小程序",
* "appAvatar": "https:\/\/www.finogeeks.club\/statics\/images\/swan_mini\/swan_logo.png",
* "appId": "5df36b3f687c5c00013e9fd1",
* "userId": "finogeeks",
* "params": {
* "title": "apt-test-tweet-接口测试发布的动态!@#¥%……&*(",
* "desc": "您身边的服务专家",
* "imageUrl": "finfile:\/\/tmp_fc15edd8-2ff6-4c54-9ee9-fe5ee034033d1576550313667.png",
* "path": "pages\/tweet\/tweet-detail.html?fcid=%40staff_staff1%3A000000.finogeeks.com&timelineId=db0c2098-031e-41c4-b9c6-87a5bbcf681d&shareId=3dfa2f78-19fc-42fc-b3a9-4779a6dac654",
* "appInfo": {
* "weixin": {
* "path": "\/studio\/pages\/tweet\/tweet-detail",
* "query": {
* "fcid": "@staff_staff1:000000.finogeeks.com",
* "timelineId": "db0c2098-031e-41c4-b9c6-87a5bbcf681d"
* }
* }
* }
* }
* }
* @param bitmap 小程序封面图片。如果[appInfo].params.imageUrl字段为http、https的链接地址,那么小程序封面图片
* 就取[appInfo].params.imageUrl对应的图片,否则小程序的封面图片取[bitmap]。
* @param callback 转发小程序结果回调。
*/
@Override
public void onRegisteredMoreMenuItemClicked(@NotNull String appId, @NotNull String path, @NotNull String menuItemId, @Nullable String appInfo, @Nullable Bitmap bitmap, @NotNull IAppletCallback callback) {
Toast.makeText(mContext, "小程序" + appId + "的" + path + "页面的菜单" + menuItemId + "被点击了,appInfo : " + appInfo + " bitmap : " + bitmap, Toast.LENGTH_SHORT).show();
callback.onSuccess(null);
}
/**
* 转发小程序
*
* @param appInfo 小程序信息,是一串json,包含了小程序id、小程序名称、小程序图标、用户id、转发的数据内容等信息。
* [appInfo]的内容格式如下:
* {
* "appTitle": "凡泰小程序",
* "appAvatar": "https:\/\/www.finogeeks.club\/statics\/images\/swan_mini\/swan_logo.png",
* "appId": "5df36b3f687c5c00013e9fd1",
* "userId": "finogeeks",
* "params": {
* "title": "apt-test-tweet-接口测试发布的动态!@#¥%……&*(",
* "desc": "您身边的服务专家",
* "imageUrl": "finfile:\/\/tmp_fc15edd8-2ff6-4c54-9ee9-fe5ee034033d1576550313667.png",
* "path": "pages\/tweet\/tweet-detail.html?fcid=%40staff_staff1%3A000000.finogeeks.com&timelineId=db0c2098-031e-41c4-b9c6-87a5bbcf681d&shareId=3dfa2f78-19fc-42fc-b3a9-4779a6dac654",
* "appInfo": {
* "weixin": {
* "path": "\/studio\/pages\/tweet\/tweet-detail",
* "query": {
* "fcid": "@staff_staff1:000000.finogeeks.com",
* "timelineId": "db0c2098-031e-41c4-b9c6-87a5bbcf681d"
* }
* }
* }
* }
* }
* @param bitmap 小程序封面图片。如果[appInfo].params.imageUrl字段为http、https的链接地址,那么小程序封面图片
* 就取[appInfo].params.imageUrl对应的图片,否则小程序的封面图片取[bitmap]。
* @param callback 转发小程序结果回调。
*/
@Override
public void shareAppMessage(@NotNull String appInfo, @Nullable Bitmap bitmap, @NotNull IAppletCallback callback) {
Toast.makeText(mContext, "点击了转发按钮,去实现您的转发/分享逻辑吧", Toast.LENGTH_SHORT).show();
}
@Override
public void chooseAvatar(@NonNull IAppletCallback iAppletCallback) {
}
@Override
public boolean contact(@NonNull JSONObject jsonObject) {
return false;
}
@Override
public boolean feedback(@NonNull Bundle bundle) {
return false;
}
@Override
public void getJSSDKConfig(@NonNull JSONObject jsonObject, @NonNull IAppletCallback iAppletCallback) {
}
@Override
public void getPhoneNumber(@NonNull IAppletCallback iAppletCallback) {
}
@androidx.annotation.Nullable
@Override
public Map<String, String> getWebViewCookie(@NonNull String s) {
return null;
}
@Override
public boolean launchApp(@androidx.annotation.Nullable String s) {
return false;
}
}
================================================
FILE: app/src/main/java/com/finogeeks/mop/demo/InputContentActivity.java
================================================
package com.finogeeks.mop.demo;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
/**
* 输入内容页面
*/
public class InputContentActivity extends AppCompatActivity {
public static final String EXTRA_NAME_INPUT_CONTENT = "input_content";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_input_content);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
final EditText editTextInputContent = findViewById(R.id.edt_input_content);
Button btnConfirm = findViewById(R.id.btn_confirm);
btnConfirm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (editTextInputContent.length() < 1) {
Toast.makeText(InputContentActivity.this, getString(R.string.fin_clip_input_content_hint), Toast.LENGTH_SHORT).show();
return;
}
Intent intent = new Intent();
intent.putExtra(EXTRA_NAME_INPUT_CONTENT, editTextInputContent.getText().toString());
setResult(RESULT_OK, intent);
finish();
}
});
}
}
================================================
FILE: app/src/main/java/com/finogeeks/mop/demo/MainActivity.java
================================================
package com.finogeeks.mop.demo;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import com.finogeeks.lib.applet.client.FinAppClient;
import com.finogeeks.lib.applet.sdk.api.request.IFinAppletRequest;
import java.util.HashMap;
import java.util.Map;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
Button btnScan = findViewById(R.id.btn_scan);
btnScan.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, ScanStartAppletActivity.class));
}
});
Button btnCharts = findViewById(R.id.btn_charts);
btnCharts.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FinAppClient.INSTANCE.getAppletApiManager().startApplet(MainActivity.this, IFinAppletRequest.Companion.fromAppId("5facb3a52dcbff00017469bd"),null);
}
});
Button btnDemo = findViewById(R.id.btn_demo);
btnDemo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FinAppClient.INSTANCE.getAppletApiManager().startApplet(MainActivity.this,IFinAppletRequest.Companion.fromAppId( "5fa214a29a6a7900019b5cc1"),null);
}
});
Button btnProfile = findViewById(R.id.btn_profile);
btnProfile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FinAppClient.INSTANCE.getAppletApiManager().startApplet(MainActivity.this, IFinAppletRequest.Companion.fromAppId("5fa215459a6a7900019b5cc3"),null);
}
});
Button btnCustomApi = findViewById(R.id.btn_custom_api);
btnCustomApi.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Map<String, String> params = new HashMap<>();
params.put("path", "pages/index/index");
FinAppClient.INSTANCE.getAppletApiManager().startApplet(MainActivity.this, IFinAppletRequest.Companion.fromAppId("5fc8934aefb8c600019e9747").setStartParams(params),null);
}
});
Button btnH5Api = findViewById(R.id.btn_h5_api);
btnH5Api.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Map<String, String> params = new HashMap<>();
params.put("path", "pages/webview/webview");
FinAppClient.INSTANCE.getAppletApiManager().startApplet(MainActivity.this, "5fc8934aefb8c600019e9747", params,null);
}
});
Button btnAppletLogin = findViewById(R.id.btn_applet_login);
btnAppletLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FinAppClient.INSTANCE.getAppletApiManager().startApplet(MainActivity.this, "60f051ea525ea10001c0bd22",null);
}
});
}
}
================================================
FILE: app/src/main/java/com/finogeeks/mop/demo/MopApplication.java
================================================
package com.finogeeks.mop.demo;
import android.app.Activity;
import android.graphics.Color;
import android.widget.Toast;
import androidx.multidex.MultiDexApplication;
import com.finogeeks.lib.applet.client.FinAppClient;
import com.finogeeks.lib.applet.client.FinAppConfig;
import com.finogeeks.lib.applet.client.FinAppProcessClient;
import com.finogeeks.lib.applet.interfaces.FinCallback;
import com.finogeeks.lib.applet.interfaces.IApi;
import com.finogeeks.lib.applet.sdk.api.IAppletApiManager;
import com.finogeeks.mop.demo.customapi.CustomApi;
import com.finogeeks.mop.demo.customapi.CustomH5Api;
import com.finogeeks.mop.demo.customapi.user.LoginApi;
import com.finogeeks.mop.demo.customapi.user.ProfileApi;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
public class MopApplication extends MultiDexApplication {
@Override
public void onCreate() {
super.onCreate();
if (FinAppClient.INSTANCE.isFinAppProcess(this)) {
// 小程序进程
// 小程序进程中注册api的方法能获取到小程序所在activity对象,可以用做创建对话框的context参数)
FinAppProcessClient.INSTANCE.setCallback(new FinAppProcessClient.Callback() {
@Override
public List<IApi> getRegisterExtensionApis(@NotNull Activity activity) {
ArrayList<IApi> apis = new ArrayList<>();
apis.add(new LoginApi(activity));
apis.add(new ProfileApi());
return apis;
}
@Nullable
@Override
public List<IApi> getRegisterExtensionWebApis(@NotNull Activity activity) {
return null;
}
});
return;
}
FinAppConfig.UIConfig uiConfig = new FinAppConfig.UIConfig();
uiConfig.setHideNavigationBarCloseButton(true);
uiConfig.setHideBackHome(true);
uiConfig.setHideForwardMenu(true);
uiConfig.setHideFeedbackAndComplaints(true);
uiConfig.setMoreMenuStyle(FinAppConfig.UIConfig.MORE_MENU_DEFAULT);
FinAppConfig.UIConfig.CapsuleConfig capsuleConfig = new FinAppConfig.UIConfig.CapsuleConfig();
capsuleConfig.capsuleWidth = 86f;
capsuleConfig.capsuleHeight = 31f;
capsuleConfig.capsuleRightMargin = 15f;
capsuleConfig.capsuleCornerRadius = 15.5f;
capsuleConfig.capsuleBorderWidth = 0.5f;
capsuleConfig.capsuleBgLightColor = Color.BLACK;
capsuleConfig.capsuleBgDarkColor = Color.WHITE;
capsuleConfig.capsuleBorderLightColor = Color.parseColor("#88ffffff");
capsuleConfig.capsuleBorderDarkColor = Color.parseColor("#a5a9b4");
capsuleConfig.moreLightImage = R.mipmap.more_light;
capsuleConfig.moreDarkImage = R.mipmap.more_dark;
capsuleConfig.moreBtnWidth = 25f;
capsuleConfig.moreBtnLeftMargin = 11f;
capsuleConfig.closeLightImage = R.mipmap.close_light;
capsuleConfig.closeDarkImage = R.mipmap.close_dark;
capsuleConfig.closeBtnWidth = 25f;
capsuleConfig.closeBtnLeftMargin = 9f;
capsuleConfig.capsuleDividerLightColor = Color.parseColor("#88ffffff");
capsuleConfig.capsuleDividerDarkColor = Color.parseColor("#a5a9b4");
uiConfig.setCapsuleConfig(capsuleConfig);
FinAppConfig config = new FinAppConfig.Builder()
.setSdkKey(BuildConfig.APP_KEY)
.setSdkSecret(BuildConfig.APP_SECRET)
.setApiUrl(BuildConfig.API_URL)
.setApiPrefix(BuildConfig.API_PREFIX)
.setDebugMode(BuildConfig.DEBUG)
.setUiConfig(uiConfig)
.setEncryptionType(FinAppConfig.ENCRYPTION_TYPE_SM)
.build();
FinAppClient.INSTANCE.init(this, config, new FinCallback<Object>() {
@Override
public void onSuccess(Object result) {
Toast.makeText(MopApplication.this, "SDK初始化成功", Toast.LENGTH_SHORT).show();
// 注册自定义小程序API
FinAppClient.INSTANCE.getExtensionApiManager().registerApi(new CustomApi(MopApplication.this));
// 注册自定义H5 API
FinAppClient.INSTANCE.getExtensionWebApiManager().registerApi(new CustomH5Api(MopApplication.this));
// 设置IAppletHandler实现类
FinAppClient.INSTANCE.setAppletHandler(new AppletHandler(getApplicationContext()));
// 在主进程设置"小程序进程调用主进程"的处理方法
// 开发者也可以选择在主进程其他合适的代码位置设置处理方法
FinAppClient.INSTANCE.getAppletApiManager()
.setAppletProcessCallHandler(new IAppletApiManager.AppletProcessCallHandler() {
@Override
public void onAppletProcessCall(@NotNull String name,
@Nullable String params,
@Nullable FinCallback<String> callback) {
if (callback != null) {
if (name.equals(LoginApi.API_NAME_LOGIN)) {
// 从主进程获取登录信息,返回给小程序进程
// 这里返回的是虚拟的用户登录信息,开发者请从APP里面自行获取用户登录信息
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("userId", "123");
} catch (JSONException e) {
e.printStackTrace();
}
callback.onSuccess(jsonObject.toString());
}
}
}
});
}
@Override
public void onError(int code, String error) {
Toast.makeText(MopApplication.this, "SDK初始化失败", Toast.LENGTH_SHORT).show();
}
@Override
public void onProgress(int status, String error) {
}
});
}
}
================================================
FILE: app/src/main/java/com/finogeeks/mop/demo/ScanQRCodeActivity.kt
================================================
package com.finogeeks.mop.demo
import android.Manifest
import android.app.Activity
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.os.VibrationEffect
import android.os.Vibrator
import android.util.Log
import android.view.MenuItem
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import cn.bingoogolapple.qrcode.core.QRCodeView
import com.finogeeks.lib.applet.modules.permission.checkPermissions
import kotlinx.android.synthetic.main.activity_scan_qr_code.*
/**
* 扫描二维码页面
*/
class ScanQRCodeActivity : AppCompatActivity(), QRCodeView.Delegate {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_scan_qr_code)
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
override fun onStart() {
super.onStart()
checkPermissions(Manifest.permission.CAMERA, granted = {
zBarView.visibility = View.VISIBLE
zBarView.setDelegate(this)
zBarView.startCamera()
zBarView.startSpotAndShowRect()
})
}
override fun onStop() {
zBarView.stopCamera()
super.onStop()
}
override fun onDestroy() {
zBarView.onDestroy()
super.onDestroy()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
zBarView.showScanRect()
}
override fun onScanQRCodeSuccess(result: String?) {
vibrate()
zBarView.startSpot()
setResult(Activity.RESULT_OK, Intent().putExtra(EXTRA_RESULT, result))
finish()
}
override fun onCameraAmbientBrightnessChanged(isDark: Boolean) {
var tipText: String = zBarView.scanBoxView.tipText
val ambientBrightnessTip = "\n环境过暗,请打开闪光灯"
if (isDark) {
if (!tipText.contains(ambientBrightnessTip)) {
zBarView.scanBoxView.tipText = tipText + ambientBrightnessTip
}
} else {
if (tipText.contains(ambientBrightnessTip)) {
tipText = tipText.substring(0, tipText.indexOf(ambientBrightnessTip))
zBarView.scanBoxView.tipText = tipText
}
}
}
override fun onScanQRCodeOpenCameraError() {
Toast.makeText(this, "打开相机出错", Toast.LENGTH_SHORT).show()
}
private fun vibrate() {
val vibrator = getSystemService(VIBRATOR_SERVICE) as Vibrator
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
@Suppress("DEPRECATION")
vibrator.vibrate(200)
} else {
try {
val effect = VibrationEffect.createOneShot(
200,
VibrationEffect.DEFAULT_AMPLITUDE
)
vibrator.vibrate(effect, null)
} catch (iae: IllegalArgumentException) {
Log.e(TAG, "Failed to create VibrationEffect", iae)
}
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
onBackPressed()
return true
}
return super.onOptionsItemSelected(item)
}
companion object {
private const val TAG = "ScanQRCodeActivity"
const val EXTRA_RESULT = "result"
}
}
================================================
FILE: app/src/main/java/com/finogeeks/mop/demo/ScanStartAppletActivity.kt
================================================
package com.finogeeks.mop.demo
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.MenuItem
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.finogeeks.lib.applet.client.FinAppClient
import com.finogeeks.lib.applet.interfaces.FinCallback
import com.finogeeks.lib.applet.sdk.api.request.IFinAppletRequest
import kotlinx.android.synthetic.main.activity_scan_start_applet.*
/**
* 扫码启动小程序的页面
*/
@SuppressLint("Registered")
open class ScanStartAppletActivity : AppCompatActivity() {
private var isStartingApplet = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_scan_start_applet)
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
btnScan.setOnClickListener { scanQRCode() }
}
private fun scanQRCode() {
startActivityForResult(Intent(this, ScanQRCodeActivity::class.java), REQ_CODE_SCAN_QR_CODE)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQ_CODE_SCAN_QR_CODE) {
if (resultCode == Activity.RESULT_OK && data != null) {
if (!isStartingApplet)
FinAppClient.appletApiManager.startApplet(this, IFinAppletRequest.fromQrCode(data.getStringExtra(ScanQRCodeActivity.EXTRA_RESULT)),
object : FinCallback<String?> {
override fun onSuccess(result: String?) {
isStartingApplet = false
runOnUiThread {
Toast.makeText(this@ScanStartAppletActivity, "扫码成功", Toast.LENGTH_SHORT).show()
}
}
override fun onError(code: Int, error: String?) {
isStartingApplet = false
runOnUiThread {
Toast.makeText(this@ScanStartAppletActivity, error, Toast.LENGTH_SHORT).show()
}
}
override fun onProgress(status: Int, info: String?) {
}
})
/*FinAppClient.appletApiManager.startAppletByQrcode(this, data.getStringExtra(ScanQRCodeActivity.EXTRA_RESULT),
object : FinCallback<String> {
override fun onSuccess(result: String?) {
isStartingApplet = false
runOnUiThread {
Toast.makeText(this@ScanStartAppletActivity, "扫码成功", Toast.LENGTH_SHORT).show()
}
}
override fun onError(code: Int, error: String?) {
isStartingApplet = false
runOnUiThread {
Toast.makeText(this@ScanStartAppletActivity, error, Toast.LENGTH_SHORT).show()
}
}
override fun onProgress(status: Int, info: String?) {
}
})*/
}
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
onBackPressed()
return true
}
return super.onOptionsItemSelected(item)
}
companion object {
private const val TAG = "StartAppletActivity"
private const val REQ_CODE_SCAN_QR_CODE = 0x01
}
}
================================================
FILE: app/src/main/java/com/finogeeks/mop/demo/customapi/CustomApi.java
================================================
package com.finogeeks.mop.demo.customapi;
import android.content.Context;
import android.content.Intent;
import androidx.annotation.NonNull;
import com.finogeeks.lib.applet.api.AbsApi;
import com.finogeeks.lib.applet.interfaces.ICallback;
import com.finogeeks.mop.demo.InputContentActivity;
import com.finogeeks.mop.demo.R;
import org.json.JSONException;
import org.json.JSONObject;
import static android.app.Activity.RESULT_OK;
import static com.finogeeks.mop.demo.InputContentActivity.EXTRA_NAME_INPUT_CONTENT;
/**
* 自定义小程序API
* 跳转到原生APP的输入内容页面{@link InputContentActivity},输入内容提交后,把输入的内容回传给小程序
*/
public class CustomApi extends AbsApi {
private static final int REQ_CODE_INPUT_CONTENT = 0x01;
private static final String API_NAME_ON_NATIVE = "onNative";
@NonNull
private Context mContext;
public CustomApi(@NonNull Context context) {
mContext = context;
}
/**
* @return 支持可调用的api名称的数组
*/
@Override
public String[] apis() {
return new String[]{API_NAME_ON_NATIVE};
}
/**
* 接收到对应的api调用时,会调用此方法,在此方法中处理api调用的功能逻辑
*
* @param event 事件名称,即api名称
* @param param 参数
* @param callback 回调接口
*/
@Override
public void invoke(String event, JSONObject param, ICallback callback) {
if (API_NAME_ON_NATIVE.equals(event)) {
Intent intent = new Intent(mContext, InputContentActivity.class);
callback.startActivityForResult(intent, REQ_CODE_INPUT_CONTENT);
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data, ICallback callback) {
super.onActivityResult(requestCode, resultCode, data, callback);
if (requestCode == REQ_CODE_INPUT_CONTENT) {
if (resultCode == RESULT_OK && data != null) {
String inputContent = data.getStringExtra(EXTRA_NAME_INPUT_CONTENT);
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("text", inputContent);
callback.onSuccess(jsonObject);
} catch (JSONException e) {
e.printStackTrace();
callback.onFail();
}
} else {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("errMsg", mContext.getString(R.string.fin_clip_get_input_content_failed));
callback.onFail(jsonObject);
} catch (JSONException e) {
e.printStackTrace();
callback.onFail();
}
}
}
}
}
================================================
FILE: app/src/main/java/com/finogeeks/mop/demo/customapi/CustomH5Api.java
================================================
package com.finogeeks.mop.demo.customapi;
import android.content.Context;
import android.content.Intent;
import androidx.annotation.NonNull;
import com.finogeeks.lib.applet.api.AbsApi;
import com.finogeeks.lib.applet.interfaces.ICallback;
import com.finogeeks.mop.demo.InputContentActivity;
import com.finogeeks.mop.demo.R;
import org.json.JSONException;
import org.json.JSONObject;
import static android.app.Activity.RESULT_OK;
import static com.finogeeks.mop.demo.InputContentActivity.EXTRA_NAME_INPUT_CONTENT;
/**
* 自定义H5 API
* 跳转到原生APP的输入内容页面{@link InputContentActivity},输入内容提交后,把输入的内容回传给小程序中的网页
*/
public class CustomH5Api extends AbsApi {
private static final int REQ_CODE_INPUT_CONTENT = 0x02;
private static final String API_NAME_USER_DEFINE_NATIVE = "user_define_native";
@NonNull
private Context mContext;
public CustomH5Api(@NonNull Context context) {
mContext = context;
}
/**
* @return 支持可调用的api名称的数组
*/
@Override
public String[] apis() {
return new String[]{API_NAME_USER_DEFINE_NATIVE};
}
/**
* 接收到对应的api调用时,会调用此方法,在此方法中处理api调用的功能逻辑
*
* @param event 事件名称,即api名称
* @param param 参数
* @param callback 回调接口
*/
@Override
public void invoke(String event, JSONObject param, ICallback callback) {
if (API_NAME_USER_DEFINE_NATIVE.equals(event)) {
Intent intent = new Intent(mContext, InputContentActivity.class);
callback.startActivityForResult(intent, REQ_CODE_INPUT_CONTENT);
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data, ICallback callback) {
super.onActivityResult(requestCode, resultCode, data, callback);
if (requestCode == REQ_CODE_INPUT_CONTENT) {
if (resultCode == RESULT_OK && data != null) {
String inputContent = data.getStringExtra(EXTRA_NAME_INPUT_CONTENT);
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("text", inputContent);
callback.onSuccess(jsonObject);
} catch (JSONException e) {
e.printStackTrace();
callback.onFail();
}
} else {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("errMsg", mContext.getString(R.string.fin_clip_get_input_content_failed));
callback.onFail(jsonObject);
} catch (JSONException e) {
e.printStackTrace();
callback.onFail();
}
}
}
}
}
================================================
FILE: app/src/main/java/com/finogeeks/mop/demo/customapi/user/LoginApi.java
================================================
package com.finogeeks.mop.demo.customapi.user;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import com.finogeeks.lib.applet.api.AbsApi;
import com.finogeeks.lib.applet.client.FinAppProcessClient;
import com.finogeeks.lib.applet.interfaces.FinCallback;
import com.finogeeks.lib.applet.interfaces.ICallback;
import org.json.JSONException;
import org.json.JSONObject;
public class LoginApi extends AbsApi {
public final static String API_NAME_LOGIN = "login"; // 小程序基础库调用的api名称
private final Activity activity;
public LoginApi(Activity activity) {
this.activity = activity;
}
@Override
public String[] apis() {
return new String[]{API_NAME_LOGIN};
}
@Override
public void invoke(String event, JSONObject param, ICallback callback) {
if (event.equals(API_NAME_LOGIN)) {
showAuthDialog(callback);
}
}
/**
* 显示获取用户登录信息的授权提示对话框
*/
private void showAuthDialog(final ICallback callback) {
// 是否需要显示授权提示对话框请开发者按照产品需求自行处理
new AlertDialog.Builder(activity)
.setTitle("是否同意授权获取用户登录信息?")
.setNegativeButton("拒绝", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
callback.onFail();
}
})
.setPositiveButton("同意", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
loginMainProcess(callback);
}
})
.show();
}
/**
* 从主进程获取用户登录信息
*/
private void loginMainProcess(final ICallback callback) {
// 小程序进程调用主进程,在主进程获取用户信息后返回给小程序进程
FinAppProcessClient.INSTANCE.getAppletProcessApiManager()
.callInMainProcess(API_NAME_LOGIN, null, new FinCallback<String>() {
@Override
public void onSuccess(final String result) {
// 需要在主线程调用callback方法
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
callback.onSuccess(new JSONObject(result));
} catch (JSONException e) {
e.printStackTrace();
callback.onFail();
}
}
});
}
@Override
public void onError(int code, String error) {
callback.onFail();
}
@Override
public void onProgress(int status, String info) {
}
});
}
}
================================================
FILE: app/src/main/java/com/finogeeks/mop/demo/customapi/user/ProfileApi.java
================================================
package com.finogeeks.mop.demo.customapi.user;
import com.finogeeks.lib.applet.api.AbsApi;
import com.finogeeks.lib.applet.interfaces.ICallback;
import org.json.JSONException;
import org.json.JSONObject;
public class ProfileApi extends AbsApi {
private final static String API_NAME_GET_USER_PROFILE = "getUserProfile"; // 小程序基础库调用的api名称
@Override
public String[] apis() {
return new String[]{API_NAME_GET_USER_PROFILE};
}
@Override
public void invoke(String event, JSONObject param, ICallback callback) {
if (event.equals(API_NAME_GET_USER_PROFILE)) {
JSONObject jsonObject = new JSONObject();
try {
// 这里返回的是虚拟的用户个人信息,开发者请从APP里面自行获取用户个人信息
jsonObject.put("nickName", "张三");
} catch (JSONException e) {
e.printStackTrace();
}
callback.onSuccess(jsonObject);
}
}
}
================================================
FILE: app/src/main/res/drawable/ic_launcher_background.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#008577"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>
================================================
FILE: app/src/main/res/drawable-v24/ic_launcher_foreground.xml
================================================
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeWidth="1"
android:strokeColor="#00000000">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
================================================
FILE: app/src/main/res/layout/activity_input_content.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:titleTextColor="@android:color/white" />
<EditText
android:id="@+id/edt_input_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:hint="@string/fin_clip_input_content_hint"
app:layout_constraintBottom_toTopOf="@+id/btn_confirm"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn_confirm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:text="@string/fin_clip_confirm"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/edt_input_content" />
</androidx.constraintlayout.widget.ConstraintLayout>
================================================
FILE: app/src/main/res/layout/activity_main.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
tools:showIn="@layout/activity_main">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:titleTextColor="@android:color/white" />
<Button
android:id="@+id/btn_scan"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/scan_start_applet"
app:layout_constraintBottom_toTopOf="@+id/btn_demo"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<Button
android:id="@+id/btn_charts"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/fin_clip_charts_applet"
app:layout_constraintBottom_toTopOf="@+id/btn_demo"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<Button
android:id="@+id/btn_demo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@string/fin_clip_demo_applet"
app:layout_constraintBottom_toTopOf="@+id/btn_profile"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_charts" />
<Button
android:id="@+id/btn_profile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@string/fin_clip_profile_applet"
app:layout_constraintBottom_toTopOf="@+id/btn_custom_api"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_demo" />
<Button
android:id="@+id/btn_custom_api"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@string/fin_clip_custom_api"
app:layout_constraintBottom_toTopOf="@+id/btn_h5_api"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_profile" />
<Button
android:id="@+id/btn_h5_api"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@string/fin_clip_custom_h5_api"
app:layout_constraintBottom_toTopOf="@+id/btn_applet_login"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_custom_api" />
<Button
android:id="@+id/btn_applet_login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@string/fin_clip_applet_login"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_h5_api" />
</androidx.constraintlayout.widget.ConstraintLayout>
================================================
FILE: app/src/main/res/layout/activity_scan_qr_code.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
style="@style/Widget.AppCompat.Toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<cn.bingoogolapple.qrcode.zbar.ZBarView
android:id="@+id/zBarView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@id/toolbar"
app:qrcv_animTime="1000"
app:qrcv_barCodeTipText="将条码放入框内,即可自动扫描"
app:qrcv_barcodeRectHeight="120dp"
app:qrcv_borderColor="@android:color/white"
app:qrcv_borderSize="1px"
app:qrcv_cornerColor="@color/colorPrimaryDark"
app:qrcv_cornerLength="20dp"
app:qrcv_cornerSize="3dp"
app:qrcv_isAutoZoom="true"
app:qrcv_isBarcode="false"
app:qrcv_isOnlyDecodeScanBoxArea="true"
app:qrcv_isShowDefaultGridScanLineDrawable="false"
app:qrcv_isShowDefaultScanLineDrawable="true"
app:qrcv_isShowLocationPoint="true"
app:qrcv_isShowTipBackground="false"
app:qrcv_isShowTipTextAsSingleLine="false"
app:qrcv_isTipTextBelowRect="true"
app:qrcv_maskColor="#4D000000"
app:qrcv_qrCodeTipText="将二维码放入框内,即可自动扫描"
app:qrcv_rectWidth="260dp"
app:qrcv_scanLineColor="@color/colorPrimaryDark"
app:qrcv_tipTextMargin="20dp"
app:qrcv_tipTextSize="12sp"
app:qrcv_toolbarHeight="@dimen/fin_applet_navbar_height"
app:qrcv_topOffset="80dp"
app:qrcv_verticalBias="-1"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>
================================================
FILE: app/src/main/res/layout/activity_scan_start_applet.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#f5f5f6">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
style="@style/Widget.AppCompat.Toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btnScan"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="40dp"
android:layout_marginEnd="10dp"
android:text="扫码打开小程序"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
================================================
FILE: app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
================================================
FILE: app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
================================================
FILE: app/src/main/res/values/colors.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#008577</color>
<color name="colorPrimaryDark">#00574B</color>
<color name="colorAccent">#D81B60</color>
</resources>
================================================
FILE: app/src/main/res/values/dimens.xml
================================================
<resources>
<dimen name="fab_margin">16dp</dimen>
</resources>
================================================
FILE: app/src/main/res/values/strings.xml
================================================
<resources>
<string name="app_name">FinClip Demo</string>
<string name="fin_clip_charts_applet">绘图小程序</string>
<string name="fin_clip_demo_applet">官方小程序</string>
<string name="fin_clip_profile_applet">智能对账单</string>
<string name="fin_clip_custom_api">自定义小程序API示例</string>
<string name="fin_clip_custom_h5_api">自定义H5 API示例</string>
<string name="fin_clip_applet_login">小程序登录授权示例</string>
<string name="fin_clip_input_content_hint">请输入内容</string>
<string name="fin_clip_confirm">确定</string>
<string name="fin_clip_get_input_content_failed">获取输入内容失败</string>
<string name="scan_start_applet">扫码打开小程序</string>
</resources>
================================================
FILE: app/src/main/res/values/styles.xml
================================================
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
</resources>
================================================
FILE: app/src/test/java/com/finogeeks/mop/demo/ExampleUnitTest.java
================================================
package com.finogeeks.mop.demo;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}
================================================
FILE: build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
maven {
url "https://gradle.finogeeks.club/repository/applet/"
credentials {
username "applet"
password "123321"
}
}
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Fri Feb 07 17:25:22 CST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
================================================
FILE: gradle.properties
================================================
# 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
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
================================================
FILE: gradlew
================================================
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
================================================
FILE: gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
================================================
FILE: settings.gradle
================================================
include ':app'
rootProject.name='mopdemo'
gitextract_95_p49xo/ ├── .github/ │ └── workflows/ │ ├── issue.yml │ └── pull_request.yml ├── .gitignore ├── .idea/ │ ├── .name │ ├── codeStyles/ │ │ └── Project.xml │ ├── compiler.xml │ ├── deploymentTargetDropDown.xml │ ├── deploymentTargetSelector.xml │ ├── gradle.xml │ ├── jarRepositories.xml │ ├── kotlinc.xml │ ├── migrations.xml │ ├── misc.xml │ ├── runConfigurations.xml │ └── vcs.xml ├── README.md ├── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ ├── release/ │ │ └── app-release.apk │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── finogeeks/ │ │ └── mop/ │ │ └── demo/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── finogeeks/ │ │ │ └── mop/ │ │ │ └── demo/ │ │ │ ├── AppletHandler.java │ │ │ ├── InputContentActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── MopApplication.java │ │ │ ├── ScanQRCodeActivity.kt │ │ │ ├── ScanStartAppletActivity.kt │ │ │ └── customapi/ │ │ │ ├── CustomApi.java │ │ │ ├── CustomH5Api.java │ │ │ └── user/ │ │ │ ├── LoginApi.java │ │ │ └── ProfileApi.java │ │ └── res/ │ │ ├── drawable/ │ │ │ └── ic_launcher_background.xml │ │ ├── drawable-v24/ │ │ │ └── ic_launcher_foreground.xml │ │ ├── layout/ │ │ │ ├── activity_input_content.xml │ │ │ ├── activity_main.xml │ │ │ ├── activity_scan_qr_code.xml │ │ │ └── activity_scan_start_applet.xml │ │ ├── mipmap-anydpi-v26/ │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ └── values/ │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test/ │ └── java/ │ └── com/ │ └── finogeeks/ │ └── mop/ │ └── demo/ │ └── ExampleUnitTest.java ├── build.gradle ├── finclip.jks ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat └── settings.gradle
SYMBOL INDEX (45 symbols across 10 files)
FILE: app/src/androidTest/java/com/finogeeks/mop/demo/ExampleInstrumentedTest.java
class ExampleInstrumentedTest (line 18) | @RunWith(AndroidJUnit4.class)
method useAppContext (line 20) | @Test
FILE: app/src/main/java/com/finogeeks/mop/demo/AppletHandler.java
class AppletHandler (line 26) | public class AppletHandler implements IAppletHandler {
method AppletHandler (line 31) | private AppletHandler() {
method AppletHandler (line 34) | public AppletHandler(@NonNull Context context) {
method getGrayAppletVersionConfigs (line 44) | @Nullable
method getRegisteredMoreMenuItems (line 56) | @Nullable
method getUserInfo (line 86) | @Nullable
method onNavigationBarCloseButtonClicked (line 97) | @Override
method onRegisteredMoreMenuItemClicked (line 135) | @Override
method shareAppMessage (line 171) | @Override
method chooseAvatar (line 176) | @Override
method contact (line 181) | @Override
method feedback (line 186) | @Override
method getJSSDKConfig (line 191) | @Override
method getPhoneNumber (line 196) | @Override
method getWebViewCookie (line 201) | @androidx.annotation.Nullable
method launchApp (line 207) | @Override
FILE: app/src/main/java/com/finogeeks/mop/demo/InputContentActivity.java
class InputContentActivity (line 17) | public class InputContentActivity extends AppCompatActivity {
method onCreate (line 21) | @Override
FILE: app/src/main/java/com/finogeeks/mop/demo/MainActivity.java
class MainActivity (line 17) | public class MainActivity extends AppCompatActivity {
method onCreate (line 19) | @Override
FILE: app/src/main/java/com/finogeeks/mop/demo/MopApplication.java
class MopApplication (line 28) | public class MopApplication extends MultiDexApplication {
method onCreate (line 30) | @Override
FILE: app/src/main/java/com/finogeeks/mop/demo/customapi/CustomApi.java
class CustomApi (line 23) | public class CustomApi extends AbsApi {
method CustomApi (line 32) | public CustomApi(@NonNull Context context) {
method apis (line 39) | @Override
method invoke (line 51) | @Override
method onActivityResult (line 59) | @Override
FILE: app/src/main/java/com/finogeeks/mop/demo/customapi/CustomH5Api.java
class CustomH5Api (line 23) | public class CustomH5Api extends AbsApi {
method CustomH5Api (line 32) | public CustomH5Api(@NonNull Context context) {
method apis (line 39) | @Override
method invoke (line 51) | @Override
method onActivityResult (line 59) | @Override
FILE: app/src/main/java/com/finogeeks/mop/demo/customapi/user/LoginApi.java
class LoginApi (line 15) | public class LoginApi extends AbsApi {
method LoginApi (line 20) | public LoginApi(Activity activity) {
method apis (line 24) | @Override
method invoke (line 29) | @Override
method showAuthDialog (line 39) | private void showAuthDialog(final ICallback callback) {
method loginMainProcess (line 61) | private void loginMainProcess(final ICallback callback) {
FILE: app/src/main/java/com/finogeeks/mop/demo/customapi/user/ProfileApi.java
class ProfileApi (line 9) | public class ProfileApi extends AbsApi {
method apis (line 13) | @Override
method invoke (line 18) | @Override
FILE: app/src/test/java/com/finogeeks/mop/demo/ExampleUnitTest.java
class ExampleUnitTest (line 12) | public class ExampleUnitTest {
method addition_isCorrect (line 13) | @Test
Condensed preview — 53 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (100K chars).
[
{
"path": ".github/workflows/issue.yml",
"chars": 446,
"preview": "name: Notify\non:\n issues:\n types: [opened]\n issue_comment:\n types: [created]\njobs:\n build:\n runs-on: ubuntu-"
},
{
"path": ".github/workflows/pull_request.yml",
"chars": 466,
"preview": "name: Notify\non:\n pull_request:\n branches: [ master ]\njobs:\n build:\n runs-on: ubuntu-latest\n steps:\n - u"
},
{
"path": ".gitignore",
"chars": 208,
"preview": "*.iml\n.gradle\n/local.properties\n/.idea/caches\n/.idea/libraries\n/.idea/modules.xml\n/.idea/workspace.xml\n/.idea/navEditor."
},
{
"path": ".idea/.name",
"chars": 7,
"preview": "mopdemo"
},
{
"path": ".idea/codeStyles/Project.xml",
"chars": 3203,
"preview": "<component name=\"ProjectCodeStyleConfiguration\">\n <code_scheme name=\"Project\" version=\"173\">\n <codeStyleSettings lan"
},
{
"path": ".idea/compiler.xml",
"chars": 169,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"CompilerConfiguration\">\n <bytecodeTar"
},
{
"path": ".idea/deploymentTargetDropDown.xml",
"chars": 541,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"deploymentTargetDropDown\">\n <runningD"
},
{
"path": ".idea/deploymentTargetSelector.xml",
"chars": 301,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"deploymentTargetSelector\">\n <selectio"
},
{
"path": ".idea/gradle.xml",
"chars": 757,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"GradleMigrationSettings\" migrationVersio"
},
{
"path": ".idea/jarRepositories.xml",
"chars": 1270,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"RemoteRepositoriesConfiguration\">\n <r"
},
{
"path": ".idea/kotlinc.xml",
"chars": 176,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"KotlinJpsPluginSettings\">\n <option na"
},
{
"path": ".idea/migrations.xml",
"chars": 254,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"ProjectMigrations\">\n <option name=\"Mi"
},
{
"path": ".idea/misc.xml",
"chars": 972,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"CMakeSettings\">\n <configurations>\n "
},
{
"path": ".idea/runConfigurations.xml",
"chars": 964,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"RunConfigurationProducerService\">\n <o"
},
{
"path": ".idea/vcs.xml",
"chars": 167,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"VcsDirectoryMappings\">\n <mapping dire"
},
{
"path": "README.md",
"chars": 7065,
"preview": "<p align=\"center\">\n <a href=\"https://www.finclip.com?from=github\">\n <img width=\"auto\" src=\"https://www.finclip.com"
},
{
"path": "app/.gitignore",
"chars": 7,
"preview": "/build\n"
},
{
"path": "app/build.gradle",
"chars": 2665,
"preview": "apply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\napply plugin: 'kotlin-android-extensions'\napply p"
},
{
"path": "app/proguard-rules.pro",
"chars": 785,
"preview": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguar"
},
{
"path": "app/src/androidTest/java/com/finogeeks/mop/demo/ExampleInstrumentedTest.java",
"chars": 760,
"preview": "package com.finogeeks.mop.demo;\n\nimport android.content.Context;\n\nimport androidx.test.platform.app.InstrumentationRegis"
},
{
"path": "app/src/main/AndroidManifest.xml",
"chars": 1578,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n package="
},
{
"path": "app/src/main/java/com/finogeeks/mop/demo/AppletHandler.java",
"chars": 7726,
"preview": "package com.finogeeks.mop.demo;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.os.Bundl"
},
{
"path": "app/src/main/java/com/finogeeks/mop/demo/InputContentActivity.java",
"chars": 1539,
"preview": "package com.finogeeks.mop.demo;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.view.View;\nimpo"
},
{
"path": "app/src/main/java/com/finogeeks/mop/demo/MainActivity.java",
"chars": 3519,
"preview": "package com.finogeeks.mop.demo;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.view.View;\nimpo"
},
{
"path": "app/src/main/java/com/finogeeks/mop/demo/MopApplication.java",
"chars": 6301,
"preview": "package com.finogeeks.mop.demo;\n\nimport android.app.Activity;\nimport android.graphics.Color;\nimport android.widget.Toast"
},
{
"path": "app/src/main/java/com/finogeeks/mop/demo/ScanQRCodeActivity.kt",
"chars": 3481,
"preview": "package com.finogeeks.mop.demo\n\nimport android.Manifest\nimport android.app.Activity\nimport android.content.Intent\nimport"
},
{
"path": "app/src/main/java/com/finogeeks/mop/demo/ScanStartAppletActivity.kt",
"chars": 3993,
"preview": "package com.finogeeks.mop.demo\n\nimport android.annotation.SuppressLint\nimport android.app.Activity\nimport android.conten"
},
{
"path": "app/src/main/java/com/finogeeks/mop/demo/customapi/CustomApi.java",
"chars": 2667,
"preview": "package com.finogeeks.mop.demo.customapi;\n\nimport android.content.Context;\nimport android.content.Intent;\n\nimport androi"
},
{
"path": "app/src/main/java/com/finogeeks/mop/demo/customapi/CustomH5Api.java",
"chars": 2712,
"preview": "package com.finogeeks.mop.demo.customapi;\n\nimport android.content.Context;\nimport android.content.Intent;\n\nimport androi"
},
{
"path": "app/src/main/java/com/finogeeks/mop/demo/customapi/user/LoginApi.java",
"chars": 3058,
"preview": "package com.finogeeks.mop.demo.customapi.user;\n\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport andr"
},
{
"path": "app/src/main/java/com/finogeeks/mop/demo/customapi/user/ProfileApi.java",
"chars": 930,
"preview": "package com.finogeeks.mop.demo.customapi.user;\n\nimport com.finogeeks.lib.applet.api.AbsApi;\nimport com.finogeeks.lib.app"
},
{
"path": "app/src/main/res/drawable/ic_launcher_background.xml",
"chars": 5606,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/src/main/res/drawable-v24/ic_launcher_foreground.xml",
"chars": 1880,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:aapt=\"http://schemas.android.com/aapt\"\n "
},
{
"path": "app/src/main/res/layout/activity_input_content.xml",
"chars": 1775,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas."
},
{
"path": "app/src/main/res/layout/activity_main.xml",
"chars": 4151,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas."
},
{
"path": "app/src/main/res/layout/activity_scan_qr_code.xml",
"chars": 2194,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas."
},
{
"path": "app/src/main/res/layout/activity_scan_start_applet.xml",
"chars": 1249,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas."
},
{
"path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
"chars": 272,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <b"
},
{
"path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
"chars": 272,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <b"
},
{
"path": "app/src/main/res/values/colors.xml",
"chars": 208,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <color name=\"colorPrimary\">#008577</color>\n <color name=\"color"
},
{
"path": "app/src/main/res/values/dimens.xml",
"chars": 67,
"preview": "<resources>\n <dimen name=\"fab_margin\">16dp</dimen>\n</resources>\n"
},
{
"path": "app/src/main/res/values/strings.xml",
"chars": 663,
"preview": "<resources>\n <string name=\"app_name\">FinClip Demo</string>\n <string name=\"fin_clip_charts_applet\">绘图小程序</string>\n "
},
{
"path": "app/src/main/res/values/styles.xml",
"chars": 708,
"preview": "<resources>\n\n <!-- Base application theme. -->\n <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar"
},
{
"path": "app/src/test/java/com/finogeeks/mop/demo/ExampleUnitTest.java",
"chars": 383,
"preview": "package com.finogeeks.mop.demo;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit te"
},
{
"path": "build.gradle",
"chars": 802,
"preview": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n r"
},
{
"path": "gradle/wrapper/gradle-wrapper.properties",
"chars": 232,
"preview": "#Fri Feb 07 17:25:22 CST 2020\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
},
{
"path": "gradle.properties",
"chars": 1073,
"preview": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will ov"
},
{
"path": "gradlew",
"chars": 5296,
"preview": "#!/usr/bin/env sh\n\n##############################################################################\n##\n## Gradle start up"
},
{
"path": "gradlew.bat",
"chars": 2260,
"preview": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@r"
},
{
"path": "settings.gradle",
"chars": 42,
"preview": "include ':app'\nrootProject.name='mopdemo'\n"
}
]
// ... and 3 more files (download for full content)
About this extraction
This page contains the full source code of the finogeeks/finclip-android-demo GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 53 files (85.8 KB), approximately 24.3k tokens, and a symbol index with 45 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.