diff --git a/.gitignore b/.gitignore index 496ee2c..00fa096 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,69 @@ -.DS_Store \ No newline at end of file +.DS_Store +### Android template +# Built application files +*.apk +*.ap_ + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ +out/ + +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +# Android Studio Navigation editor temp files +.navigation/ + +# Android Studio captures folder +captures/ + +# IntelliJ +*.iml +.idea/workspace.xml +.idea/tasks.xml +.idea/gradle.xml +.idea/dictionaries +.idea/libraries + +# Keystore files +# Uncomment the following line if you do not want to check your keystore files in. +#*.jks + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild + +# Google Services (e.g. APIs or Firebase) +google-services.json + +# Freeline +freeline.py +freeline/ +freeline_project_description.json + +/build.gradle +gradle.properties +gradlew +gradlew.bat +react-native-phone-picker.iml +settings.gradle +gradle +.idea +.gradle + diff --git a/README.md b/README.md index 106af35..15624fe 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,91 @@ # react-native-phone-picker +# 我的扩展 + +## 扩展Android 实现 + +- 动态申请权限 +- 在Android的CallBack中,是3个参数 + +```js +error{ +0:成功, +1:权限被拒绝, +2:权限被决绝,并不再询问, +3:未知错误 +} +callback(phone,name,error){ + +} +``` + +- android api 最低版本 为19 + + +## link-Android + +关于方法数超限,已经移除多余无用的库,可能不会出现了,但是如果你引入了太多的android源生模块,可能还需要这么配置 + +- android/settings.gradle +``` +include ':react-native-phone-picker' +project(':react-native-phone-picker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-phone-picker/android/') +``` +- android/app/build.gradle +``` + +android{ + defaultConfig { + // 方法数超限 + multiDexEnabled true + } +} + +dependencies { +... +//添加 + compile project(':react-native-phone-picker') +} +``` + +- MainApplication.java + +```java +//添加 +import android.support.multidex.MultiDexApplication; +//注意,方法数可能超限, +//将Application 改为 MultiDexApplication +public class MainApplication extends MultiDexApplication implements ReactApplication { + + + private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { + @Override + public boolean getUseDeveloperSupport() { + return BuildConfig.DEBUG; + } + + @Override + protected List getPackages() { + return Arrays.asList( + new MyReactPackage(), + //添加 + new PhonePickerPackage() + ); + } + + @Override + protected String getJSMainModuleName() { + return "index"; + } + }; +} + +``` + + + +# 原README + React Native component for select phone number from address book 用于React Native的通讯录手机号选取模块 diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..569c48e --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,24 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 26 + buildToolsVersion "26.0.1" + defaultConfig { + minSdkVersion 19 + targetSdkVersion 26 + versionCode 2 + versionName "1.1" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + provided 'com.android.support:appcompat-v7:26.1.0' + provided "com.facebook.react:react-native:+" +} diff --git a/android/proguard-rules.pro b/android/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/android/proguard-rules.pro @@ -0,0 +1,21 @@ +# 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 diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000..f178499 --- /dev/null +++ b/android/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/android/src/main/java/cn/yzl/reactnative/phonepicker/ErrorCode.java b/android/src/main/java/cn/yzl/reactnative/phonepicker/ErrorCode.java new file mode 100644 index 0000000..d8cc963 --- /dev/null +++ b/android/src/main/java/cn/yzl/reactnative/phonepicker/ErrorCode.java @@ -0,0 +1,24 @@ +package cn.yzl.reactnative.phonepicker; + +/** + * Created by YZL on 2018/6/2. + */ + +public interface ErrorCode { + /** + * 成功 + */ + int SUCCESS = 0; + /** + * 权限被拒绝 + */ + int PERMISSON_FAIL = 1; + /** + * 权限被拒绝,并不再询问 + */ + int PERMISSON_NOASK = 2; + /** + * 其他 + */ + int OTHER = 2; +} diff --git a/android/src/main/java/cn/yzl/reactnative/phonepicker/PhonePicker.java b/android/src/main/java/cn/yzl/reactnative/phonepicker/PhonePicker.java new file mode 100644 index 0000000..71b322d --- /dev/null +++ b/android/src/main/java/cn/yzl/reactnative/phonepicker/PhonePicker.java @@ -0,0 +1,65 @@ +/** + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.yzl.reactnative.phonepicker; + +import android.app.Activity; +import android.app.FragmentManager; +import android.support.annotation.NonNull; + +import com.facebook.react.bridge.Callback; + +public class PhonePicker { + + static final String TAG = "REACT_NATIVE_PHONE_PICKER"; + + PhonePickerFragment phonePickerFragment; + + public PhonePicker(@NonNull Activity activity) { + phonePickerFragment = getRxPermissionsFragment(activity); + } + + private PhonePickerFragment getRxPermissionsFragment(Activity activity) { + PhonePickerFragment phonePickerFragment = findRxPermissionsFragment(activity); + boolean isNewInstance = phonePickerFragment == null; + if (isNewInstance) { + phonePickerFragment = new PhonePickerFragment(); + FragmentManager fragmentManager = activity.getFragmentManager(); + fragmentManager + .beginTransaction() + .add(phonePickerFragment, TAG) + .commitAllowingStateLoss(); + fragmentManager.executePendingTransactions(); + } + return phonePickerFragment; + } + + private PhonePickerFragment findRxPermissionsFragment(Activity activity) { + return (PhonePickerFragment) activity.getFragmentManager().findFragmentByTag(TAG); + } + + public void setCallback(Callback callback) { + if (phonePickerFragment != null) { + this.phonePickerFragment.setCallBack(callback); + } + } + + public void startPicker() { + if (phonePickerFragment == null + || phonePickerFragment.isDetached()) { + return; + } + phonePickerFragment.startPicker(); + } +} \ No newline at end of file diff --git a/android/src/main/java/cn/yzl/reactnative/phonepicker/PhonePickerFragment.java b/android/src/main/java/cn/yzl/reactnative/phonepicker/PhonePickerFragment.java new file mode 100644 index 0000000..9a3c63a --- /dev/null +++ b/android/src/main/java/cn/yzl/reactnative/phonepicker/PhonePickerFragment.java @@ -0,0 +1,126 @@ +package cn.yzl.reactnative.phonepicker; + +import android.Manifest; +import android.app.Activity; +import android.app.Fragment; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.provider.ContactsContract; +import android.support.annotation.NonNull; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; + +import com.facebook.react.bridge.Callback; + +public class PhonePickerFragment extends Fragment { + + private static final int PHONE_PICKER_REQUEST_CODE = 43; + + private static final int PERMISSION_REQUEST_CODE = 44; + + private Callback callBack; + + public PhonePickerFragment() { + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setRetainInstance(true); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == PERMISSION_REQUEST_CODE) { + if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { + if (callBack != null) { + if (!ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.READ_CONTACTS)) { + //不再询问 + if (callBack != null) { + callBack.invoke(null, null, ErrorCode.PERMISSON_NOASK); + callBack = null; + } + } else { + callBack.invoke(null, null, ErrorCode.PERMISSON_FAIL); + callBack = null; + } + } + } else { + startPickerReal(); + } + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == Activity.RESULT_OK) { + if (requestCode == PHONE_PICKER_REQUEST_CODE) { + Uri uri = data.getData(); + if (uri != null) { + Cursor cursor = getActivity().getContentResolver() + .query(uri, null, + null, null, null); + cursor.moveToFirst(); + String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); + String contactId = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID)); + Cursor phoneCursor = getActivity().getContentResolver() + .query( + ContactsContract.CommonDataKinds.Phone.CONTENT_URI, + null, + ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + contactId, + null, + null); + phoneCursor.moveToFirst(); + + String number = phoneCursor.getString(phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); + + if (number != null || number.isEmpty()) { + if (name == null) { + name = ""; + } + number = number.replace(" ", ""); + if (callBack != null) { + callBack.invoke(number, name, ErrorCode.SUCCESS); + callBack = null; + } + } + } + } + } + } + + public void startPicker() { + checkPermisson(); + } + + private void startPickerReal() { + startActivityForResult(new Intent( + Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI), PHONE_PICKER_REQUEST_CODE); + } + + private void checkPermisson() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (ActivityCompat.checkSelfPermission(getActivity(), + Manifest.permission.READ_CONTACTS) + != PackageManager.PERMISSION_GRANTED) { +// 权限未授予 + requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, PERMISSION_REQUEST_CODE); + } else { + //权限已授予 + startPickerReal(); + } + } else { + startPickerReal(); + } + } + + public void setCallBack(Callback callBack) { + this.callBack = callBack; + } +} \ No newline at end of file diff --git a/android/src/main/java/cn/yzl/reactnative/phonepicker/PhonePickerModule.java b/android/src/main/java/cn/yzl/reactnative/phonepicker/PhonePickerModule.java new file mode 100644 index 0000000..e3e9e79 --- /dev/null +++ b/android/src/main/java/cn/yzl/reactnative/phonepicker/PhonePickerModule.java @@ -0,0 +1,58 @@ +package cn.yzl.reactnative.phonepicker; + +import android.app.Activity; +import android.os.Handler; +import android.os.Looper; + +import com.facebook.react.bridge.Callback; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; + +/** + * Created by YZL on 2018/6/1. + */ + +public class PhonePickerModule extends ReactContextBaseJavaModule { + + public static final String TAG = "RNPhonePicker"; + + + public PhonePickerModule(ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public String getName() { + return TAG; + } + + /** + * @param callback(name,phone,errorCode) + */ + @ReactMethod + public void selectPhoneNumber(final Callback callback) { + Activity currentActivity = getCurrentActivity(); + if (currentActivity == null || currentActivity.isDestroyed() || currentActivity.isFinishing()) { + return; + } + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + startPicker(callback); + } + }); + } + + private void startPicker(Callback callback) { + Activity currentActivity = getCurrentActivity(); + if (currentActivity == null || currentActivity.isDestroyed() || currentActivity.isFinishing()) { + return; + } + PhonePicker phonePicker = new PhonePicker(getCurrentActivity()); + phonePicker.setCallback(callback); + phonePicker.startPicker(); +// getCurrentActivity().startActivityForResult(new Intent( +// Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI), 0); + } +} diff --git a/android/src/main/java/cn/yzl/reactnative/phonepicker/PhonePickerPackage.java b/android/src/main/java/cn/yzl/reactnative/phonepicker/PhonePickerPackage.java new file mode 100644 index 0000000..d6b64d0 --- /dev/null +++ b/android/src/main/java/cn/yzl/reactnative/phonepicker/PhonePickerPackage.java @@ -0,0 +1,31 @@ +package cn.yzl.reactnative.phonepicker; + +import com.facebook.react.ReactPackage; +import com.facebook.react.bridge.JavaScriptModule; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.uimanager.ViewManager; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Created by YZL on 2018/6/1. + */ + +public class PhonePickerPackage implements ReactPackage { + @Override + public List createNativeModules(ReactApplicationContext reactContext) { + return Arrays.asList(new PhonePickerModule(reactContext)); + } + + public List> createJSModules() { + return Collections.emptyList(); + } + + @Override + public List createViewManagers(ReactApplicationContext reactContext) { + return Collections.emptyList(); + } +} diff --git a/android/src/main/res/values/strings.xml b/android/src/main/res/values/strings.xml new file mode 100644 index 0000000..64fad88 --- /dev/null +++ b/android/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + android + diff --git a/package.json b/package.json index fba92b8..ef7f2f4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-phone-picker", - "version": "0.0.3", + "version": "0.1.0", "description": "React Native component for select phone number from address book", "main": "index.js", "scripts": { @@ -8,22 +8,24 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/Spikef/react-native-phone-picker.git" + "url": "git+https://github.com/yizeliang/react-native-phone-picker.git" }, "keywords": [ "react-component", "react-native", "ios", "address", - "phone" + "phone", + "android" ], "author": { - "name": "Spikef", - "email": "Spikef@Foxmail.com" + "name": "Spikef&YiZeliang", + "email": "Spikef@Foxmail.com&zeliangyi@gmal.com" }, "license": "MIT", "bugs": { - "url": "https://github.com/silentcloud/react-native-phone-picker/issues" + "url": "https://github.com/silentcloud/react-native-phone-picker/issues", + "url2": "https://github.com/yizeliang/react-native-phone-picker/issues" }, "peerDependencies": { "react-native": ">=0.7"