@hanwha-ss1/plugin 0.1.7 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,6 +11,11 @@ npx cap sync
11
11
  ```javascript
12
12
  import { HanwhaPlugin } from "@hanwha-ss1/plugin"
13
13
 
14
+ // 앱 실행
15
+ await HanwhaPlugin.execute({
16
+ package: "패키지명"
17
+ })
18
+
14
19
  // 연락처 저장
15
20
  await HanwhaPlugin.addContact({
16
21
  name: "이름님",
@@ -20,7 +20,7 @@ apply plugin: 'com.android.library'
20
20
  android {
21
21
  compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32
22
22
  defaultConfig {
23
- minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22
23
+ minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 23
24
24
  targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32
25
25
  versionCode 1
26
26
  versionName "1.0"
@@ -52,7 +52,10 @@ dependencies {
52
52
  implementation project(':capacitor-android')
53
53
  implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
54
54
  implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
55
+ implementation 'androidx.core:core:1.6.0'
55
56
  testImplementation "junit:junit:$junitVersion"
56
57
  androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
57
58
  androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
59
+
60
+ implementation 'androidx.biometric:biometric:1.1.0'
58
61
  }
@@ -4,8 +4,11 @@
4
4
 
5
5
  <uses-permission android:name="android.permission.INTERNET"/>
6
6
  <uses-permission android:name="android.permission.READ_CONTACTS"/>
7
+ <uses-permission android:name="android.permission.USE_FINGERPRINT" />
7
8
  <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
8
9
 
10
+ <uses-permission android:name="android.permission.USE_BIOMETRIC" />
11
+
9
12
  <application>
10
13
  <activity
11
14
  android:theme="@style/AppTheme.NoActionBar"
@@ -0,0 +1,28 @@
1
+ package com.plugin.bio;
2
+
3
+ import android.app.Activity;
4
+ import android.util.Log;
5
+ import android.view.WindowManager;
6
+
7
+
8
+ public class Bio {
9
+
10
+ public interface OnResult {
11
+ void onSuccess();
12
+ void onFail(String error);
13
+ }
14
+
15
+ public String echo(String value) {
16
+ Log.i("Echo", value);
17
+ return value;
18
+ }
19
+
20
+ /**
21
+ * 바이오 인증
22
+ *
23
+ * @param activity
24
+ */
25
+ public void authenticate(Activity activity, OnResult result) {
26
+ BioAuthManager.getInstance().authenticate(activity, result);
27
+ }
28
+ }
@@ -0,0 +1,255 @@
1
+ package com.plugin.bio;
2
+
3
+ import android.Manifest;
4
+ import android.app.Activity;
5
+ import android.app.KeyguardManager;
6
+ import android.content.Context;
7
+ import android.content.Intent;
8
+ import android.content.pm.PackageManager;
9
+ import android.hardware.fingerprint.FingerprintManager;
10
+ import android.os.Build;
11
+ import android.os.CancellationSignal;
12
+ import android.provider.Settings;
13
+ import android.util.Log;
14
+
15
+ import androidx.annotation.NonNull;
16
+ import androidx.biometric.BiometricManager;
17
+ import androidx.biometric.BiometricPrompt;
18
+ import androidx.core.content.ContextCompat;
19
+ import androidx.fragment.app.FragmentActivity;
20
+
21
+ import java.util.concurrent.Executor;
22
+
23
+ import javax.crypto.Cipher;
24
+
25
+ import static android.content.Context.FINGERPRINT_SERVICE;
26
+ import static android.content.Context.KEYGUARD_SERVICE;
27
+ import static androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG;
28
+ import static androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL;
29
+
30
+ public class BioAuthManager {
31
+ private static BioAuthManager instance;
32
+
33
+ private BioAuthManager() { }
34
+
35
+ public static BioAuthManager getInstance() {
36
+ if (instance == null)
37
+ {
38
+ instance = new BioAuthManager();
39
+ }
40
+
41
+ return instance;
42
+ }
43
+
44
+ private static final int REQUEST_FINGERPRINT_ENROLLMENT_AUTH = 10;
45
+
46
+ private KeyManager keyManager;
47
+
48
+ private Executor executor;
49
+ private BiometricPrompt biometricPrompt;
50
+ private BiometricPrompt.PromptInfo promptInfo;
51
+
52
+ private FingerprintManager fingerprintManager;
53
+ private KeyguardManager keyguardManager;
54
+
55
+ private FingerprintManager.CryptoObject cryptoObject; // over api 23
56
+ private BiometricPrompt.CryptoObject bioCryptoObject; // over api 28
57
+
58
+ private boolean canAuthenticate(Activity activity){
59
+
60
+ Intent intent;
61
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
62
+ {
63
+ BiometricManager biometricManager = BiometricManager.from(activity);
64
+ switch (biometricManager.canAuthenticate(BIOMETRIC_STRONG))
65
+ {
66
+ case BiometricManager.BIOMETRIC_SUCCESS:
67
+ Log.d("MY_APP_TAG", "App can authenticate using biometrics.");
68
+ return true;
69
+ case BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE:
70
+ Log.e("MY_APP_TAG", "No biometric features available on this device.");
71
+ return false;
72
+ case BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE:
73
+ Log.e("MY_APP_TAG", "Biometric features are currently unavailable.");
74
+ return false;
75
+ case BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED:
76
+ // Prompts the user to create credentials that your app accepts.
77
+ Log.d("MY_APP_TAG", "enrolled biometric doesn't existed. please enroll");
78
+
79
+ intent = new Intent(Settings.ACTION_FINGERPRINT_ENROLL);
80
+ intent.putExtra(Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED,
81
+ BIOMETRIC_STRONG | DEVICE_CREDENTIAL);
82
+ activity.startActivityForResult(intent, REQUEST_FINGERPRINT_ENROLLMENT_AUTH);
83
+ return false;
84
+ }
85
+ }
86
+ else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
87
+ {
88
+ if (!fingerprintManager.isHardwareDetected()) // 지문을 사용할 수 없는 디바이스인 경우
89
+ {
90
+ Log.d("fingerprint", "it is not device that can use fingerprint");
91
+ return false;
92
+ }
93
+ // 지문 인증 사용을 거부한 경우
94
+ else if (ContextCompat.checkSelfPermission(activity, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED)
95
+ {
96
+ Log.d("fingerprint", "permission denied");
97
+ return false;
98
+ }
99
+ else if (!keyguardManager.isKeyguardSecure()) // 잠금 화면이 설정되지 않은 경우
100
+ {
101
+ Log.d("fingerprint", "please set lock screen");
102
+ return false;
103
+ }
104
+ else if (!fingerprintManager.hasEnrolledFingerprints()) // 등록된 지문이 없는 경우
105
+ {
106
+ Log.d("fingerprint", "please enroll fingerprint");
107
+ intent = new Intent(Settings.ACTION_SECURITY_SETTINGS);
108
+ activity.startActivityForResult(intent, REQUEST_FINGERPRINT_ENROLLMENT_AUTH);
109
+ return false;
110
+ }
111
+
112
+ return true;
113
+ }
114
+
115
+ return false;
116
+ }
117
+
118
+
119
+ public void authenticate(Activity activity, Bio.OnResult callback) {
120
+
121
+ keyManager = KeyManager.getInstance();
122
+ // api 28 ( ANDROID 9.0 ) 이상은 biometricPrompt 사용
123
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
124
+ Log.d("bioAuth", "start biometricPrompt");
125
+
126
+ if (canAuthenticate(activity))
127
+ {
128
+ executor = ContextCompat.getMainExecutor(activity);
129
+
130
+ biometricPrompt = new BiometricPrompt((FragmentActivity) activity, executor, new BiometricPrompt.AuthenticationCallback() {
131
+ @Override
132
+ public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
133
+ super.onAuthenticationError(errorCode, errString);
134
+ Log.d("bioAuth", errString.toString());
135
+ if(callback != null) {
136
+ callback.onFail(errString.toString());
137
+ }
138
+ }
139
+
140
+ @Override
141
+ public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
142
+ super.onAuthenticationSucceeded(result);
143
+ Log.d("bioAuth", "auth success");
144
+ if(callback != null) {
145
+ callback.onSuccess();
146
+ }
147
+ }
148
+
149
+ @Override
150
+ public void onAuthenticationFailed() {
151
+ super.onAuthenticationFailed();
152
+ Log.d("bioAuth", "auth failed");
153
+ if(callback != null) {
154
+ callback.onFail("auth failed");
155
+ }
156
+ }
157
+ });
158
+
159
+ // DEVICE_CREDENTIAL 및 BIOMETRIC_STRING | DEVICE_CREDENTIAL 은 안드로이드 10 이하에서 지원되지 않는다.
160
+ // 안드로이드 10 이하에서 PIN 이나 패턴, 비밀번호가 있는지 확인하려면 KeyguardManager.isDeviceSecure() 함수를 사용할 것
161
+ promptInfo = new BiometricPrompt.PromptInfo.Builder()
162
+ .setTitle("지문 인증")
163
+ .setSubtitle("기기에 등록된 지문을 이용하여 지문을 인증해주세요.")
164
+ .setDescription("생체 인증 설명")
165
+ // BIOMETRIC_STRONG 은 안드로이드 11 에서 정의한 클래스 3 생체 인식을 사용하는 인증 - 암호회된 키 필요
166
+ // BIOMETRIC_WEAK 은 안드로이드 11 에서 정의한 클래스 2 생체 인식을 사용하는 인증 - 암호화된 키까지 필요하지는 않음
167
+ // DEVICE_CREDENTIAL 은 화면 잠금 사용자 인증 정보를 사용하는 인증 - 사용자의 PIN, 패턴 또는 비밀번호
168
+ .setAllowedAuthenticators(BIOMETRIC_STRONG)
169
+ .setConfirmationRequired(false) // 명시적인 사용자 작업 ( 생체 인식 전 한번더 체크 ) 없이 인증할건지 default : true
170
+ .setNegativeButtonText("취소")
171
+ .build();
172
+
173
+ keyManager.generateKey();
174
+
175
+ if (keyManager.cipherInit())
176
+ {
177
+ bioCryptoObject = new BiometricPrompt.CryptoObject(keyManager.getCipher());
178
+ biometricPrompt.authenticate(promptInfo, bioCryptoObject);
179
+ }
180
+
181
+ biometricPrompt.authenticate(promptInfo);
182
+ }
183
+
184
+ }
185
+ else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)// api 23 ( ANDROID 6.0 ) 부터 api 28 ( ANDROID 9.0 ) 까지는 fingerprint 사용
186
+ {
187
+ Log.d("fingerprint", "fingerprint start");
188
+
189
+ fingerprintManager = (FingerprintManager) activity.getSystemService(FINGERPRINT_SERVICE);
190
+ keyguardManager = (KeyguardManager) activity.getSystemService(KEYGUARD_SERVICE);
191
+ // if (!fingerprintManager.isHardwareDetected()) // 지문을 사용할 수 없는 디바이스인 경우
192
+ // {
193
+ // Log.d("fingerprint", "it is not device that can use fingerprint");
194
+ // }
195
+ // // 지문 인증 사용을 거부한 경우
196
+ // else if (ContextCompat.checkSelfPermission(context, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED)
197
+ // {
198
+ // Log.d("fingerprint", "permission denied");
199
+ // }
200
+ // else if (!keyguardManager.isKeyguardSecure()) // 잠금 화면이 설정되지 않은 경우
201
+ // {
202
+ // Log.d("fingerprint", "please set lock screen");
203
+ // }
204
+ // else if (!fingerprintManager.hasEnrolledFingerprints()) // 등록된 지문이 없는 경우
205
+ // {
206
+ // Log.d("fingerprint", "please enroll fingerprint");
207
+ // }
208
+ // else
209
+ if (canAuthenticate(activity))
210
+ {
211
+ Log.d("fingerprint", "requirement fingerprint needed all pass");
212
+
213
+ keyManager.generateKey();
214
+
215
+ if (keyManager.cipherInit())
216
+ {
217
+
218
+ Cipher cipher = keyManager.getCipher();
219
+
220
+ cryptoObject = new FingerprintManager.CryptoObject(cipher);
221
+
222
+ fingerprintManager.authenticate(cryptoObject, new CancellationSignal(), 0, new FingerprintManager.AuthenticationCallback() {
223
+ @Override
224
+ public void onAuthenticationError(int errorCode, CharSequence errString) {
225
+ super.onAuthenticationError(errorCode, errString);
226
+ Log.d("fingerprint", String.valueOf(errorCode));
227
+ }
228
+
229
+ @Override
230
+ public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
231
+ super.onAuthenticationSucceeded(result);
232
+ Log.d("fingerprint", "auth success");
233
+
234
+ }
235
+
236
+ @Override
237
+ public void onAuthenticationFailed() {
238
+ super.onAuthenticationFailed();
239
+ Log.d("fingerprint", "auth failed");
240
+
241
+ }
242
+
243
+ @Override
244
+ public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
245
+ super.onAuthenticationHelp(helpCode, helpString);
246
+ Log.d("fingerprint", helpString.toString());
247
+ }
248
+
249
+ }, null);
250
+ }
251
+
252
+ }
253
+ }
254
+ }
255
+ }
@@ -0,0 +1,47 @@
1
+ package com.plugin.bio;
2
+
3
+ import com.getcapacitor.JSObject;
4
+ import com.getcapacitor.Plugin;
5
+ import com.getcapacitor.PluginCall;
6
+ import com.getcapacitor.PluginMethod;
7
+ import com.getcapacitor.annotation.CapacitorPlugin;
8
+
9
+
10
+ @CapacitorPlugin(name = "Bio")
11
+ public class BioPlugin extends Plugin{
12
+ private Bio implementation = new Bio();
13
+
14
+ @PluginMethod
15
+ public void echo(PluginCall call) {
16
+ String value = call.getString("value");
17
+
18
+ JSObject ret = new JSObject();
19
+ ret.put("value", implementation.echo(value));
20
+ call.resolve(ret);
21
+ }
22
+
23
+ @PluginMethod
24
+ public void authenticate(PluginCall call) {
25
+ if(implementation == null) {
26
+ implementation = new Bio();
27
+ }
28
+ implementation.authenticate(getActivity(), new Bio.OnResult() {
29
+ @Override
30
+ public void onSuccess() {
31
+ JSObject ret = new JSObject();
32
+ ret.put("result", true);
33
+ ret.put("message", "완료");
34
+ call.resolve(ret);
35
+ }
36
+
37
+ @Override
38
+ public void onFail(String error) {
39
+ JSObject ret = new JSObject();
40
+ ret.put("result", false);
41
+ ret.put("message", error);
42
+ call.resolve(ret);
43
+ }
44
+ });
45
+
46
+ }
47
+ }
@@ -0,0 +1,80 @@
1
+ package com.plugin.bio;
2
+
3
+ import android.security.keystore.KeyGenParameterSpec;
4
+ import android.security.keystore.KeyProperties;
5
+
6
+ import java.security.KeyStore;
7
+
8
+ import javax.crypto.Cipher;
9
+ import javax.crypto.KeyGenerator;
10
+ import javax.crypto.SecretKey;
11
+
12
+ public class KeyManager {
13
+ private static KeyManager instance;
14
+
15
+ private KeyManager() { };
16
+
17
+ public static KeyManager getInstance() {
18
+ if (instance == null)
19
+ {
20
+ instance = new KeyManager();
21
+ }
22
+
23
+ return instance;
24
+ }
25
+
26
+ private static final String KEY_NAME = "BIOAUTH_KEY";
27
+ private KeyStore keyStore;
28
+ private KeyGenerator keyGenerator;
29
+
30
+ private Cipher cipher;
31
+
32
+ public Cipher getCipher() {
33
+ return cipher;
34
+ }
35
+
36
+ /**
37
+ * 지문 인증을 사용하기 위한 키를 생성하는 함수
38
+ */
39
+ public void generateKey() {
40
+ try {
41
+
42
+ // 안드로이드에서 기본적으로 제공하는 KeyStore 인듯하다 ( AndroidKeyStore )
43
+ keyStore = KeyStore.getInstance("AndroidKeyStore");
44
+ keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
45
+
46
+ keyStore.load(null);
47
+ keyGenerator.init(new KeyGenParameterSpec.Builder(
48
+ KEY_NAME,
49
+ KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
50
+ .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
51
+ .setUserAuthenticationRequired(true)
52
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
53
+ .build());
54
+ keyGenerator.generateKey();
55
+
56
+ } catch (Exception e) {
57
+ e.printStackTrace();
58
+ }
59
+ }
60
+
61
+ /**
62
+ * 키스토어 저장된 키를 암호화하는 함수
63
+ * @return Boolean
64
+ */
65
+ public Boolean cipherInit() {
66
+ try {
67
+ cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
68
+ + KeyProperties.BLOCK_MODE_CBC + "/"
69
+ + KeyProperties.ENCRYPTION_PADDING_PKCS7);
70
+
71
+ SecretKey key = (SecretKey) keyStore.getKey(KEY_NAME, null);
72
+ cipher.init(Cipher.ENCRYPT_MODE, key);
73
+ return true;
74
+ } catch (Exception e) {
75
+ e.printStackTrace();
76
+ }
77
+
78
+ return false;
79
+ }
80
+ }
@@ -0,0 +1,37 @@
1
+ package com.plugin.linker;
2
+
3
+ import android.app.Activity;
4
+ import android.content.Intent;
5
+ import android.util.Log;
6
+
7
+
8
+ public class Linker {
9
+
10
+ public String echo(String value) {
11
+ Log.i("Echo", value);
12
+ return value;
13
+ }
14
+
15
+ public interface OnResult {
16
+ void onSuccess();
17
+ void onFail();
18
+ }
19
+
20
+ /**
21
+ * 앱 실행
22
+ *
23
+ * @param activity
24
+ * @param packageName 패키지명
25
+ */
26
+ public void execute(Activity activity, String packageName, OnResult result) {
27
+ try{
28
+ Intent intent = activity.getPackageManager().getLaunchIntentForPackage(packageName);
29
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
30
+ activity.startActivity(intent);
31
+ result.onSuccess();
32
+ }
33
+ catch (Exception e){
34
+ result.onFail();
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,47 @@
1
+ package com.plugin.linker;
2
+
3
+ import com.getcapacitor.JSObject;
4
+ import com.getcapacitor.Plugin;
5
+ import com.getcapacitor.PluginCall;
6
+ import com.getcapacitor.PluginMethod;
7
+ import com.getcapacitor.annotation.CapacitorPlugin;
8
+
9
+
10
+ @CapacitorPlugin(name = "Plugin")
11
+ public class LinkerPlugin extends Plugin{
12
+ private Linker implementation = new Linker();
13
+
14
+ @PluginMethod
15
+ public void echo(PluginCall call) {
16
+ String value = call.getString("value");
17
+
18
+ JSObject ret = new JSObject();
19
+ ret.put("value", implementation.echo(value));
20
+ call.resolve(ret);
21
+ }
22
+
23
+ @PluginMethod
24
+ public void execute(PluginCall call) {
25
+ String packageName = call.getString("package");
26
+ if(implementation == null) {
27
+ implementation = new Linker();
28
+ }
29
+ implementation.execute(getActivity(), packageName, new Linker.OnResult() {
30
+ @Override
31
+ public void onSuccess() {
32
+ JSObject ret = new JSObject();
33
+ ret.put("result", true);
34
+ ret.put("message", "완료");
35
+ call.resolve(ret);
36
+ }
37
+
38
+ @Override
39
+ public void onFail() {
40
+ JSObject ret = new JSObject();
41
+ ret.put("result", false);
42
+ ret.put("message", "존재하는 앱입니다.");
43
+ call.resolve(ret);
44
+ }
45
+ });
46
+ }
47
+ }
@@ -1,4 +1,13 @@
1
1
  export interface Plugin {
2
+ /**
3
+ * 앱 실행
4
+ * @param options package : 패키지명
5
+ */
6
+ execute(options: {
7
+ package: string;
8
+ }): Promise<{
9
+ value: string;
10
+ }>;
2
11
  /**
3
12
  * 연락처 저장
4
13
  * @param options name : 성명
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["export interface Plugin {\n /**\n * 연락처 저장\n * @param options name : 성명\n * @param options phone : 전화번호\n * @param options email : 이메일\n * @param options dept : 소속\n * @param options ext : 내선번호\n */\n addContact(options: {\n name: string;\n phone: string;\n email: string;\n dept: string;\n ext: string;\n }): Promise<{ value: string }>;\n\n\n /**\n * 캡쳐 방지\n * @param options disabled : 캡쳐 방지 여부 (true, false)\n */\n setScreenCaptureDisabled(options: {\n disabled: string;\n }): Promise<{ value: string }>;\n}\n"]}
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["export interface Plugin {\n /**\n * 앱 실행\n * @param options package : 패키지명\n */\n execute(options: {\n package: string;\n }): Promise<{ value: string }>;\n\n /**\n * 연락처 저장\n * @param options name : 성명\n * @param options phone : 전화번호\n * @param options email : 이메일\n * @param options dept : 소속\n * @param options ext : 내선번호\n */\n addContact(options: {\n name: string;\n phone: string;\n email: string;\n dept: string;\n ext: string;\n }): Promise<{ value: string }>;\n\n\n /**\n * 캡쳐 방지\n * @param options disabled : 캡쳐 방지 여부 (true, false)\n */\n setScreenCaptureDisabled(options: {\n disabled: string;\n }): Promise<{ value: string }>;\n}\n"]}
package/dist/esm/web.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { WebPlugin } from '@capacitor/core';
2
2
  import type { Plugin } from './definitions';
3
3
  export declare class PluginWeb extends WebPlugin implements Plugin {
4
+ execute(): Promise<any>;
4
5
  addContact(): Promise<any>;
5
6
  setScreenCaptureDisabled(): Promise<any>;
6
7
  }
package/dist/esm/web.js CHANGED
@@ -1,6 +1,9 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-vars */
2
2
  import { WebPlugin } from '@capacitor/core';
3
3
  export class PluginWeb extends WebPlugin {
4
+ async execute() {
5
+ return { results: {} };
6
+ }
4
7
  async addContact() {
5
8
  return { results: {} };
6
9
  }
@@ -1 +1 @@
1
- {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,OAAO,SAAU,SAAQ,SAAS;IAEtC,KAAK,CAAC,UAAU;QACd,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,wBAAwB;QAC5B,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACzB,CAAC;CACF","sourcesContent":["/* eslint-disable @typescript-eslint/no-unused-vars */\nimport { WebPlugin } from '@capacitor/core';\nimport type { Plugin } from './definitions';\nexport class PluginWeb extends WebPlugin implements Plugin {\n\n async addContact(): Promise<any> {\n return { results: {} };\n }\n\n async setScreenCaptureDisabled(): Promise<any> {\n return { results: {} };\n }\n}\n"]}
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,OAAO,SAAU,SAAQ,SAAS;IAEtC,KAAK,CAAC,OAAO;QACX,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,UAAU;QACd,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,wBAAwB;QAC5B,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACzB,CAAC;CACF","sourcesContent":["/* eslint-disable @typescript-eslint/no-unused-vars */\nimport { WebPlugin } from '@capacitor/core';\nimport type { Plugin } from './definitions';\nexport class PluginWeb extends WebPlugin implements Plugin {\n\n async execute(): Promise<any> {\n return { results: {} };\n }\n\n async addContact(): Promise<any> {\n return { results: {} };\n }\n\n async setScreenCaptureDisabled(): Promise<any> {\n return { results: {} };\n }\n}\n"]}
@@ -10,6 +10,9 @@ const HanwhaPlugin = core.registerPlugin('Plugin', {
10
10
 
11
11
  /* eslint-disable @typescript-eslint/no-unused-vars */
12
12
  class PluginWeb extends core.WebPlugin {
13
+ async execute() {
14
+ return { results: {} };
15
+ }
13
16
  async addContact() {
14
17
  return { results: {} };
15
18
  }
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst HanwhaPlugin = registerPlugin('Plugin', {\n web: () => import('./web').then(m => new m.PluginWeb()),\n});\nexport * from './definitions';\nexport { HanwhaPlugin };\n//# sourceMappingURL=index.js.map","/* eslint-disable @typescript-eslint/no-unused-vars */\nimport { WebPlugin } from '@capacitor/core';\nexport class PluginWeb extends WebPlugin {\n async addContact() {\n return { results: {} };\n }\n async setScreenCaptureDisabled() {\n return { results: {} };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;;;AACK,MAAC,YAAY,GAAGA,mBAAc,CAAC,QAAQ,EAAE;AAC9C,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,SAAS,EAAE,CAAC;AAC3D,CAAC;;ACHD;AAEO,MAAM,SAAS,SAASC,cAAS,CAAC;AACzC,IAAI,MAAM,UAAU,GAAG;AACvB,QAAQ,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;AAC/B,KAAK;AACL,IAAI,MAAM,wBAAwB,GAAG;AACrC,QAAQ,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;AAC/B,KAAK;AACL;;;;;;;;;"}
1
+ {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst HanwhaPlugin = registerPlugin('Plugin', {\n web: () => import('./web').then(m => new m.PluginWeb()),\n});\nexport * from './definitions';\nexport { HanwhaPlugin };\n//# sourceMappingURL=index.js.map","/* eslint-disable @typescript-eslint/no-unused-vars */\nimport { WebPlugin } from '@capacitor/core';\nexport class PluginWeb extends WebPlugin {\n async execute() {\n return { results: {} };\n }\n async addContact() {\n return { results: {} };\n }\n async setScreenCaptureDisabled() {\n return { results: {} };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;;;AACK,MAAC,YAAY,GAAGA,mBAAc,CAAC,QAAQ,EAAE;AAC9C,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,SAAS,EAAE,CAAC;AAC3D,CAAC;;ACHD;AAEO,MAAM,SAAS,SAASC,cAAS,CAAC;AACzC,IAAI,MAAM,OAAO,GAAG;AACpB,QAAQ,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;AAC/B,KAAK;AACL,IAAI,MAAM,UAAU,GAAG;AACvB,QAAQ,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;AAC/B,KAAK;AACL,IAAI,MAAM,wBAAwB,GAAG;AACrC,QAAQ,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;AAC/B,KAAK;AACL;;;;;;;;;"}
package/dist/plugin.js CHANGED
@@ -7,6 +7,9 @@ var capacitorContact = (function (exports, core) {
7
7
 
8
8
  /* eslint-disable @typescript-eslint/no-unused-vars */
9
9
  class PluginWeb extends core.WebPlugin {
10
+ async execute() {
11
+ return { results: {} };
12
+ }
10
13
  async addContact() {
11
14
  return { results: {} };
12
15
  }
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst HanwhaPlugin = registerPlugin('Plugin', {\n web: () => import('./web').then(m => new m.PluginWeb()),\n});\nexport * from './definitions';\nexport { HanwhaPlugin };\n//# sourceMappingURL=index.js.map","/* eslint-disable @typescript-eslint/no-unused-vars */\nimport { WebPlugin } from '@capacitor/core';\nexport class PluginWeb extends WebPlugin {\n async addContact() {\n return { results: {} };\n }\n async setScreenCaptureDisabled() {\n return { results: {} };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AACK,UAAC,YAAY,GAAGA,mBAAc,CAAC,QAAQ,EAAE;IAC9C,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,SAAS,EAAE,CAAC;IAC3D,CAAC;;ICHD;IAEO,MAAM,SAAS,SAASC,cAAS,CAAC;IACzC,IAAI,MAAM,UAAU,GAAG;IACvB,QAAQ,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAC/B,KAAK;IACL,IAAI,MAAM,wBAAwB,GAAG;IACrC,QAAQ,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAC/B,KAAK;IACL;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst HanwhaPlugin = registerPlugin('Plugin', {\n web: () => import('./web').then(m => new m.PluginWeb()),\n});\nexport * from './definitions';\nexport { HanwhaPlugin };\n//# sourceMappingURL=index.js.map","/* eslint-disable @typescript-eslint/no-unused-vars */\nimport { WebPlugin } from '@capacitor/core';\nexport class PluginWeb extends WebPlugin {\n async execute() {\n return { results: {} };\n }\n async addContact() {\n return { results: {} };\n }\n async setScreenCaptureDisabled() {\n return { results: {} };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AACK,UAAC,YAAY,GAAGA,mBAAc,CAAC,QAAQ,EAAE;IAC9C,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,SAAS,EAAE,CAAC;IAC3D,CAAC;;ICHD;IAEO,MAAM,SAAS,SAASC,cAAS,CAAC;IACzC,IAAI,MAAM,OAAO,GAAG;IACpB,QAAQ,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAC/B,KAAK;IACL,IAAI,MAAM,UAAU,GAAG;IACvB,QAAQ,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAC/B,KAAK;IACL,IAAI,MAAM,wBAAwB,GAAG;IACrC,QAAQ,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAC/B,KAAK;IACL;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,10 @@
1
+ import Foundation
2
+ import UIKit
3
+
4
+
5
+ @objc public class Contact: NSObject {
6
+ @objc public func echo(_ value: String) -> String {
7
+ print(value)
8
+ return value
9
+ }
10
+ }
@@ -5,5 +5,4 @@
5
5
  // each method the plugin supports using the CAP_PLUGIN_METHOD macro.
6
6
  CAP_PLUGIN(Plugin, "Plugin",
7
7
  CAP_PLUGIN_METHOD(addContact, CAPPluginReturnPromise);
8
- CAP_PLUGIN_METHOD(setScreenCaptureDisabled, CAPPluginReturnPromise);
9
8
  )
@@ -1,13 +1,13 @@
1
1
  import Foundation
2
2
  import Capacitor
3
+ import Contacts
3
4
  /**
4
5
  * Please read the Capacitor iOS Plugin Development Guide
5
6
  * here: https://capacitorjs.com/docs/plugins/ios
6
7
  */
7
8
  @objc(Plugin)
8
9
  public class Plugin: CAPPlugin {
9
- private let contact = Contact()
10
- private let screenCapture = PreventCapture()
10
+ private let implementation = Contact()
11
11
 
12
12
  @objc func addContact(_ call: CAPPluginCall) {
13
13
  let name = call.getString("name") ?? ""
@@ -16,7 +16,7 @@ public class Plugin: CAPPlugin {
16
16
  let dept = call.getString("dept") ?? ""
17
17
  let ext = call.getString("ext") ?? ""
18
18
 
19
- contact.saveContact(name: name, phone: phone, email: email, dept: dept, ext: ext) { success in
19
+ saveContact(name: name, phone: phone, email: email, dept: dept, ext: ext) { success in
20
20
  if success {
21
21
  call.resolve([
22
22
  "result": true,
@@ -29,25 +29,116 @@ public class Plugin: CAPPlugin {
29
29
  ])
30
30
  }
31
31
  }
32
+
33
+
32
34
  }
33
35
 
34
- @objc func setScreenCaptureDisabled(_ call: CAPPluginCall) {
35
- screenCapture.screenCapturePrevent(view: self.bridge?.viewController!.view ?? self.webView!) { success in
36
- if success {
37
- call.resolve([
38
- "result": true,
39
- "message": "완료"
40
- ])
36
+ private func saveContact(name: String, phone: String, email: String, dept: String, ext: String, completion: @escaping (Bool) -> Void) {
37
+
38
+ let store = CNContactStore()
39
+
40
+ // Permission 획득
41
+ store.requestAccess(for: .contacts) { (granted, error) in
42
+ guard granted else {
43
+ completion(false)
44
+ return
45
+ }
46
+
47
+ if self.getContactsMatchingPhoneNumber(phone) {
48
+
49
+ let contact: CNMutableContact = self.getNewContact(name, phone, email, dept, ext)
50
+
51
+ let request = CNSaveRequest()
52
+ request.add(contact, toContainerWithIdentifier: nil)
53
+
54
+ do {
55
+ try store.execute(request)
56
+ completion(true)
57
+ } catch {
58
+
59
+ completion(false)
60
+ }
41
61
  } else {
42
- call.resolve([
43
- "result": false,
44
- "message": "실패"
45
- ])
62
+ completion(false)
46
63
  }
47
64
  }
65
+ }
66
+ // 새로 등록할 주소록 생성
67
+ private func getNewContact(_ m_name: String, _ m_phone: String, _ m_email: String, _ m_dept: String, _ m_ext: String) -> CNMutableContact {
68
+ let contact = CNMutableContact()
69
+ contact.givenName = m_name
70
+
71
+ let phone = CNLabeledValue(label:CNLabelPhoneNumberMobile,
72
+ value:CNPhoneNumber(stringValue:m_phone))
73
+ let workLabel = "직장"
74
+ let tel = CNLabeledValue(label:workLabel,
75
+ value:CNPhoneNumber(stringValue:m_ext))
76
+ contact.phoneNumbers = [phone, tel]
48
77
 
78
+ contact.emailAddresses = [CNLabeledValue(label:CNLabelWork, value:m_email as NSString)]
79
+ contact.organizationName = m_dept
49
80
 
81
+
82
+
83
+ return contact
50
84
  }
51
-
85
+
86
+ func getContactsMatchingPhoneNumber(_ phone: String) -> Bool {
87
+ var result = true
88
+
89
+ let store = CNContactStore()
90
+ let keysToFetch: [CNKeyDescriptor] = [CNContactGivenNameKey as CNKeyDescriptor, CNContactFamilyNameKey as CNKeyDescriptor, CNContactPhoneNumbersKey as CNKeyDescriptor]
91
+
92
+
93
+ do {
94
+ let fetchRequest = CNContactFetchRequest(keysToFetch: keysToFetch)
95
+ try store.enumerateContacts(with: fetchRequest) { contact, _ in
96
+
97
+ for phoneNumber in contact.phoneNumbers {
98
+
99
+
100
+ let label = phoneNumber.label ?? "Phone"
101
+ let value = phoneNumber.value.stringValue
102
+
103
+ if value == phone {
104
+ print("Name: \(contact.givenName) \(contact.familyName)")
105
+ print("\(label): \(value )")
106
+ result = false
107
+ }
108
+ }
109
+ }
110
+ } catch {
111
+ print("Error fetching contacts: \(error)")
112
+ }
113
+
114
+ return result
115
+ }
116
+ //
117
+ // let store = CNContactStore()
118
+ // let keysToFetch: [CNKeyDescriptor] = [CNContactGivenNameKey as CNKeyDescriptor, CNContactFamilyNameKey as CNKeyDescriptor, CNContactPhoneNumbersKey as CNKeyDescriptor]
119
+ //
120
+ // // 전화번호에 일치하는 연락처를 검색하기 위한 NSPredicate를 생성
121
+ // let predicate = CNContact.predicateForContacts(withIdentifiers: [phoneNumber])
122
+ //
123
+ // do {
124
+ // // 모든 연락처 가져오기
125
+ // let allContacts = try store.unifiedContacts(matching: predicate, keysToFetch: keysToFetch)
126
+ //
127
+ // // 전화번호와 일치하는 연락처를 선택
128
+ // for contact in allContacts {
129
+ // for phoneNumberValue in contact.phoneNumbers {
130
+ // let number = phoneNumberValue.value
131
+ // if number.stringValue.contains(phoneNumber) {
132
+ // matchingContacts.append(contact)
133
+ // break
134
+ // }
135
+ // }
136
+ // }
137
+ // } catch {
138
+ // // 검색 중 오류 처리
139
+ // }
140
+ //
141
+ // return matchingContacts
142
+ // }
52
143
  }
53
144
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanwha-ss1/plugin",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Plugin",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",
@@ -1,87 +0,0 @@
1
- import Foundation
2
- import UIKit
3
- import Contacts
4
-
5
- @objc public class Contact: NSObject {
6
-
7
- @objc public func saveContact(name: String, phone: String, email: String, dept: String, ext: String, completion: @escaping (Bool) -> Void) {
8
-
9
- let store = CNContactStore()
10
-
11
- // Permission 획득
12
- store.requestAccess(for: .contacts) { (granted, error) in
13
- guard granted else {
14
- completion(false)
15
- return
16
- }
17
-
18
- if self.getContactsMatchingPhoneNumber(phone) {
19
-
20
- let contact: CNMutableContact = self.getNewContact(name, phone, email, dept, ext)
21
-
22
- let request = CNSaveRequest()
23
- request.add(contact, toContainerWithIdentifier: nil)
24
-
25
- do {
26
- try store.execute(request)
27
- completion(true)
28
- } catch {
29
-
30
- completion(false)
31
- }
32
- } else {
33
- completion(false)
34
- }
35
- }
36
- }
37
- // 새로 등록할 주소록 생성
38
- private func getNewContact(_ m_name: String, _ m_phone: String, _ m_email: String, _ m_dept: String, _ m_ext: String) -> CNMutableContact {
39
- let contact = CNMutableContact()
40
- contact.givenName = m_name
41
-
42
- let phone = CNLabeledValue(label:CNLabelPhoneNumberMobile,
43
- value:CNPhoneNumber(stringValue:m_phone))
44
- let workLabel = "직장"
45
- let tel = CNLabeledValue(label:workLabel,
46
- value:CNPhoneNumber(stringValue:m_ext))
47
- contact.phoneNumbers = [phone, tel]
48
-
49
- contact.emailAddresses = [CNLabeledValue(label:CNLabelWork, value:m_email as NSString)]
50
- contact.organizationName = m_dept
51
-
52
-
53
-
54
- return contact
55
- }
56
-
57
- func getContactsMatchingPhoneNumber(_ phone: String) -> Bool {
58
- var result = true
59
-
60
- let store = CNContactStore()
61
- let keysToFetch: [CNKeyDescriptor] = [CNContactGivenNameKey as CNKeyDescriptor, CNContactFamilyNameKey as CNKeyDescriptor, CNContactPhoneNumbersKey as CNKeyDescriptor]
62
-
63
-
64
- do {
65
- let fetchRequest = CNContactFetchRequest(keysToFetch: keysToFetch)
66
- try store.enumerateContacts(with: fetchRequest) { contact, _ in
67
-
68
- for phoneNumber in contact.phoneNumbers {
69
-
70
-
71
- let label = phoneNumber.label ?? "Phone"
72
- let value = phoneNumber.value.stringValue
73
-
74
- if value == phone {
75
- print("Name: \(contact.givenName) \(contact.familyName)")
76
- print("\(label): \(value )")
77
- result = false
78
- }
79
- }
80
- }
81
- } catch {
82
- print("Error fetching contacts: \(error)")
83
- }
84
-
85
- return result
86
- }
87
- }
@@ -1,30 +0,0 @@
1
- import Foundation
2
- import UIKit
3
- import WebKit
4
-
5
- @objc public class PreventCapture: NSObject {
6
-
7
- @objc public func screenCapturePrevent(view: UIView, completion: @escaping (Bool) -> Void) {
8
- view.makeSecure()
9
- completion(true)
10
- }
11
- }
12
-
13
- extension UIView {
14
- @objc public func makeSecure() {
15
- DispatchQueue.main.async {
16
- let textField = UITextField()
17
- textField.isSecureTextEntry = true
18
- self.addSubview(textField)
19
-
20
- if UIDevice.current.userInterfaceIdiom == .phone {
21
- textField.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
22
- textField.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
23
- }
24
-
25
- self.layer.superlayer?.insertSublayer(textField.layer, at: 0)
26
- textField.layer.sublayers?.last?.addSublayer(self.layer)
27
-
28
- }
29
- }
30
- }
Binary file
Binary file
File without changes