原生APP源码双端实战:通讯录、相册、短信、定位与前后端联调
发布时间:2026/10/2 11:03:45来源:尧图网络
简介这是一套面向移动端开发者的原生APP源码合集涵盖安卓与iOS双端重点实现通讯录、相册视频、短信及地理位置等敏感权限数据的获取并附带完整前后端代码适合研究移动端权限调用与数据采集的技术人员参考。资源包共2022个文件以Python脚本、C与H头文件、文本说明、Markdown文档、HTML与JS页面为主另有少量JSON、CSS及文档文件压缩包约532.61MB目录结构便于按模块查阅。目前已有1447人学习下载。后端基于Linux CentOS7.6、宝塔面板、Nginx、PHP7.2与MySQL5.7搭建运行目录public伪静态选ThinkPHP并开启SSL安卓端为原生纯源码iOS端为uniapp源码后台为PHP。数据库配置位于/config/database.phpRedis需设密码timibbs并重启若后台无记录可在AnLei.php中替换项目名称。iOS端实测可获取通讯录、相册与位置短信未能获取正式运行需购买Dcloud相册插件。整体适合作为权限调用与前后端联调的研究素材。1. 一套原生 APP 源码为什么比跨平台方案更值得拆去年帮一个做本地生活服务的朋友看项目他花了两周用跨平台方案搭出来的 Demo在安卓低端机上滑动通讯录直接掉到 20 帧相册选图超过 200 张就 OOM。后来换了一套原生 APP 源码重做同样的功能安卓中端机稳定 55 帧以上iOS 上权限弹窗和系统相册的衔接也顺了很多。这就是原生 APP 源码的价值——它把安卓和苹果两端的系统能力直接暴露给你通讯录、相册视频、短信、地理位置这些模块不用再靠插件桥接性能和权限可控性完全不是一个量级。这套资源包含安卓和苹果双端原生源码外加配套前后端覆盖通讯录读取、相册视频访问、短信、地理位置这几类高频系统能力。适合两类人一是想快速搭一个带系统权限交互的 APP 骨架的开发者二是需要研究原生权限申请、数据回传、前后端对接完整链路的从业者。下面我按实际拆包和跑通的顺序把这份源码怎么用、参数怎么调、坑在哪讲清楚。2. 双端原生工程结构拆解从目录到权限声明2.1 安卓端工程结构与关键目录拿到源码先别急着点运行先把目录结构过一遍。安卓端一般是标准 Gradle 工程核心目录集中在app/src/main/java和app/src/main/AndroidManifest.xml。通讯录、相册、短信、定位这几个模块通常各自独立成包方便你按需裁剪。# 安卓端典型目录结构以实际源码为准 app/ ├── src/main/ │ ├── java/com/xxx/app/ │ │ ├── contacts/ # 通讯录读取模块 │ │ ├── media/ # 相册视频访问模块 │ │ ├── sms/ # 短信模块 │ │ ├── location/ # 地理位置模块 │ │ └── MainActivity.java │ ├── res/ # 布局与资源 │ └── AndroidManifest.xml # 权限声明集中地 ├── build.gradle # 模块依赖 └── settings.gradle逻辑说明每个功能模块独立成包意味着你可以只保留需要的模块删掉其余包和对应权限声明即可瘦身。参数说明build.gradle里的minSdkVersion决定你能用哪些 API通讯录和短信相关 API 在低版本上行为差异较大常见做法是设到 23 以上避免运行时权限的兼容分支过多。2.2 苹果端工程结构与 Info.plist 权限描述苹果端是 Xcode 工程核心在.xcodeproj和Info.plist。iOS 的权限不像安卓那样集中在 Manifest而是分散在Info.plist的用途描述字段里缺一个系统就直接拒绝弹窗。!-- Info.plist 中必须声明的权限用途描述 -- keyNSContactsUsageDescription/key string需要访问通讯录以展示联系人列表/string keyNSPhotoLibraryUsageDescription/key string需要访问相册以选择图片和视频/string keyNSLocationWhenInUseUsageDescription/key string需要获取位置以提供附近服务/string逻辑说明iOS 每个敏感权限都要求一段面向用户的说明文字系统弹窗会原样展示。参数说明NSLocationWhenInUseUsageDescription是使用期间定位如果你需要后台持续定位还得加NSLocationAlwaysAndWhenInUseUsageDescription但后台定位审核严格非必要不加。短信模块在 iOS 上无法直接读取收件箱只能调起发送界面这点和安卓有本质区别后面避坑章节会细说。2.3 前后端接口约定与数据流向前后端源码里客户端负责采集系统数据服务端负责接收和存储。常见做法是客户端把通讯录、位置等数据序列化成 JSON通过 HTTP POST 提交服务端用对应的接口接收。// 客户端上报地理位置与通讯录的请求体示例 const payload { deviceId: unique-device-id, location: { lat: 39.9042, lng: 116.4074, accuracy: 15 }, contacts: [ { name: 张三, phone: 13800000000 } ], timestamp: Date.now() }; // POST /api/report Content-Type: application/json逻辑说明deviceId用于服务端区分设备location里的accuracy是定位精度米contacts是数组服务端建表时注意手机号字段长度。参数说明时间戳用毫秒服务端做幂等处理时以deviceId timestamp做唯一键比较稳妥。数据流向是单向采集上报服务端一般不反向下发指令这样接口最简单也最不容易出权限和合规问题。3. 通讯录、相册视频、短信、定位四模块实操3.1 通讯录读取安卓 ContentResolver 与 iOS CNContactStore安卓读通讯录走ContentResolver查询ContactsContractiOS 走CNContactStore。两端都要先申请权限再查询最后映射成统一的数据结构。// 安卓查询通讯录联系人姓名与电话 Cursor cursor getContentResolver().query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, new String[]{ ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER }, null, null, null ); while (cursor ! null cursor.moveToNext()) { String name cursor.getString(0); String phone cursor.getString(1); // 存入本地列表或上报 } if (cursor ! null) cursor.close();逻辑说明查询的是Phone.CONTENT_URI它把联系人和电话合并返回一个联系人多个号码会出现多行。参数说明new String[]里只取需要的列别用*否则大数据量下内存涨得快。cursor.close()必须调用否则反复查询会泄漏。iOS 端用CNContactStore的unifiedContacts方法取givenName和phoneNumbers注意 iOS 联系人可能没有姓名要做空值兜底。3.2 相册视频访问MediaStore 与 PHAsset 的取舍安卓用MediaStore.Video.Media和MediaStore.Images.Media查询相册iOS 用PHAsset。这里的关键是分页一次性拉全部媒体文件在低端机上必崩。// 安卓分页查询相册视频每页 50 条 String[] projection { MediaStore.Video.Media._ID, MediaStore.Video.Media.DISPLAY_NAME, MediaStore.Video.Media.DURATION }; Cursor cursor getContentResolver().query( MediaStore.Video.Media.EXTERNAL_CONTENT_URI, projection, null, null, MediaStore.Video.Media.DATE_ADDED DESC ); // 配合 LIMIT 或游标分批读取避免一次性加载逻辑说明按DATE_ADDED倒序最近拍的排前面符合用户预期。参数说明DURATION是视频时长毫秒图片没有这个字段。分页常见做法是用LIMIT配合偏移或者用_ID做游标。iOS 端PHFetchOptions里设sortDescriptors按创建时间倒序fetchLimit控制单次数量缩略图用PHImageManager异步取别在主线程同步取原图。3.3 短信与定位能力边界和参数设置短信模块在安卓上可以读content://sms/inbox但 iOS 完全不允许读取只能调起MFMessageComposeViewController发短信。定位两端都用系统定位框架安卓FusedLocationProviderClientiOSCLLocationManager。// 安卓读取短信收件箱仅安卓需 READ_SMS 权限 Cursor cursor getContentResolver().query( Uri.parse(content://sms/inbox), new String[]{address, body, date}, null, null, date DESC );逻辑说明address是发件号码body是短信内容date是时间戳。参数说明安卓 10 以上对短信权限收得很紧应用商店上架基本要求你是默认短信应用才给READ_SMS所以这个模块更适合内部工具或企业分发场景。定位参数里setInterval控制上报间隔太短耗电太长位置漂移常见做法是 30 秒到 1 分钟一次精度用PRIORITY_BALANCED_POWER_ACCURACY平衡功耗。4. 前后端联调与数据落库接口、字段与验证4.1 服务端接口设计与字段映射服务端接收客户端上报的数据接口设计要简单直接。常见做法是每个数据类型一个接口或者统一一个上报接口按type区分。-- 通讯录上报落库表结构示例 CREATE TABLE contacts_report ( id BIGINT PRIMARY KEY AUTO_INCREMENT, device_id VARCHAR(64) NOT NULL, contact_name VARCHAR(128), contact_phone VARCHAR(32), report_time BIGINT, INDEX idx_device (device_id) );逻辑说明device_id建索引因为查询和去重都靠它。参数说明contact_phone用VARCHAR(32)而不是数字类型因为号码可能有86前缀或带横线。report_time用毫秒时间戳存BIGINT避免时区问题。位置数据单独建表字段包含经纬度、精度、上报时间经纬度用DECIMAL(10,7)保证精度。4.2 联调步骤与返回码约定联调时先跑通一个模块再逐个加。建议顺序是定位 → 通讯录 → 相册 → 短信因为定位最简单短信最受限。# 用 curl 模拟客户端上报验证服务端接口 curl -X POST http://your-server/api/report \ -H Content-Type: application/json \ -d {deviceId:test-001,location:{lat:39.9,lng:116.4,accuracy:15}}逻辑说明先用固定deviceId测确认服务端能正确解析和落库。参数说明返回码约定0成功、1001参数缺失、1002设备未注册客户端根据返回码决定是否重试。重试要有上限常见做法是失败重试 3 次间隔递增避免弱网下疯狂请求把服务端打挂。4.3 数据验证怎么确认采集到的数据是对的采集类功能最怕数据是错的但你看不出来。验证方法是在客户端加一个本地日志把采集到的原始数据和上报数据都打出来对比服务端收到的。// 客户端上报前打印便于和服务端比对 console.log(上报前数据:, JSON.stringify(payload)); // 服务端收到后也打印一条两边对时间戳逻辑说明时间戳是最可靠的比对锚点客户端和服务端各打一条能快速定位是采集错了还是传输丢了。参数说明日志里手机号做脱敏只留后四位避免日志泄露。验证通讯录时先在自己手机上手动数一下联系人数和上报条数对比差太多就是查询条件或权限有问题。5. 避坑与常见问题排查5.1 权限弹窗不出现或直接被拒现象调用通讯录或相册接口系统权限弹窗根本不弹直接返回空数据或报错。原因安卓漏了AndroidManifest.xml里的权限声明或者 iOS 漏了Info.plist的用途描述。解决安卓检查uses-permission是否齐全iOS 检查对应的NSxxxUsageDescription是否存在缺一个系统就静默拒绝。另外安卓 6.0 以上必须运行时动态申请只在 Manifest 声明不够。5.2 相册加载大量图片导致内存暴涨现象进入相册页面滑动几十张后 APP 卡死或闪退。原因一次性把原图加载进内存没有做分页和缩略图。解决查询时分页每页 50 条左右显示用缩略图安卓用Glide或Picasso带override尺寸iOS 用PHImageManager的requestImage指定targetSize别用requestImageData取原图。5.3 定位在室内或弱信号下拿不到坐标现象定位回调一直不返回或者返回的精度是几百米。原因室内 GPS 信号弱只靠 GPS 定位拿不到。解决用融合定位安卓FusedLocationProviderClient会自动结合 WiFi 和基站iOS 的CLLocationManager设desiredAccuracy为kCLLocationAccuracyHundredMeters别一上来就要求最高精度。同时加超时兜底比如 10 秒没结果就用最后已知位置。5.4 短信模块在 iOS 上完全读不到现象iOS 端短信模块没有任何数据返回。原因iOS 系统层面就不允许第三方 APP 读取短信收件箱这是系统限制不是代码问题。解决iOS 端只能调起发送界面把「读取短信」改成「发送短信」功能或者直接去掉该模块。如果业务强依赖读取短信只能做安卓端iOS 端用其他方式替代。5.5 前后端时间戳对不上导致数据错乱现象服务端收到的数据时间顺序混乱或者同一条数据重复入库。原因客户端用了本地时间不同设备时区或系统时间不准。解决统一用 UTC 毫秒时间戳客户端取System.currentTimeMillis()或Date().timeIntervalSince1970 * 1000服务端入库前不做时区转换展示时再按用户时区格式化。去重用deviceId 业务字段 时间戳做唯一约束。6. 进阶把采集频率和上报策略调成可控参数跑通之后真正影响体验的是采集频率和上报策略。我一般会把它们抽成配置项而不是写死在代码里。安卓端可以放BuildConfig或远程配置iOS 放UserDefaults或远程配置这样不发版就能调。参数建议值说明定位上报间隔3060 秒太短耗电太长位置漂移通讯录同步频率每天 1 次或手动触发通讯录变化不频繁没必要高频相册扫描页大小50 条兼顾加载速度和内存上报失败重试次数3 次间隔 2s、4s、8s 递增单次上报数据上限500 条超过分批避免请求体过大验证策略是否合理有个简单办法在弱网环境比如限速到 2G下跑一遍看上报是否堆积、重试是否失控。我习惯在客户端加一个待上报队列网络恢复后按顺序补发队列长度设上限超过就丢弃最旧的避免无限增长。还有一个容易忽略的点是权限被用户手动关闭后的处理。用户可能在系统设置里关掉通讯录权限这时 APP 再调用会直接报错。正确做法是每次调用前检查权限状态被拒时给一个引导去设置的提示而不是反复弹窗骚扰。安卓用checkSelfPermissioniOS 用authorizationStatus两端逻辑类似。从那以后我每次拿到一套带系统权限的源码都强制先跑一遍权限拒绝和弱网这两个场景确认兜底逻辑在再去看功能本身。这套双端源码把通讯录、相册视频、短信、定位和前后端链路都铺开了适合拿来当骨架改也适合拆开研究单个模块。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网