
简介NFC碰一碰同城拓客系统是一套基于手机NFC技术的小程序与PHP后端源码资源专为本地生活商户、营销服务商及开发者打造旨在解决同城获客难、门店曝光不足等痛点。包内共2000个文件以PHP后端逻辑、HTML营销页面、JavaScript交互脚本、小程序WXML/WXSS组件及PNG/SVG图片等资源为主压缩包大小约20.05MB目录覆盖后端、前端及小程序模块便于按需部署与二次开发。目前已有834人学习下载适合关注NFC应用或本地营销系统的开发者参考。源码支持碰一碰唤起营销页面、一键发布抖音视频、小红书种草文案、跳转添加微信好友、连接门店WiFi并可引导用户前往大众点评帮助商家快速提升口碑与曝光同时包含完整的NFC触发与小程序跳转示例配合清晰的项目结构可直接用于搭建同城拓客平台或改造为其他行业版本。1. NFC碰一碰同城拓客系统把“碰一下”变成可追踪的客户线索这套系统的核心逻辑很简单把传统地推用的二维码换成一片指甲盖大小的NFC卡片用户手机贴一下卡片微信直接弹出商家的小程序页面后台同时记录这张卡是谁的、放在哪个位置、带来多少次访问、有没有授权手机号。对做本地生活服务、门店获客、同城拓客的团队来说源码的价值在于把“物理接触”和“线上留资”整条链路打通了让每一张卡片都变成可追踪的渠道入口。源码包包含小程序前端、后端接口、数据库脚本和NFC写入说明适合有基础开发能力的个人或小团队直接部署和二次开发。读完这篇你会知道它怎么跑起来、参数在哪里改以及最容易翻车的几个环节。2. 技术链路与选型NFC标签、NDEF与三条跳转路径2.1 标签型号怎么选NTAG213/215/216的参数边界先解决硬件选型。NFC碰一碰的物理载体是一张PVC卡或亚克力贴片里面封装的是NFC芯片。同城拓客场景里最常见的三种芯片是NTAG213、NTAG215、NTAG216容量分别是144字节、504字节、888字节。只写一条跳转URL的话NDEF格式下只需几十字节理论上213就够用。但实际投放我一般推荐215写卡工具兼容性更好而且留了空间以后加写门店名称、投放位置等场景描述。216的单价更高除非要做多记录或者加密存储否则没必要上。芯片型号可用存储典型用途同城拓客建议NTAG213144字节单条URL、电子名片预算紧、只跳转可用NTAG215504字节URL附加文本推荐余量充足NTAG216888字节多记录、加密数据特殊业务才考虑选型之外还有个常被忽略的参数射频灵敏度。同样标注支持NFC的手机在不同品牌上对标签的唤醒距离差别很大有些国产机型对NTAG213的识别距离特别短要找准位置才能响应。215在这个问题上表现相对稳定这也是我做投放优先选215的原因。线上能改的代码都好说线下的卡片识别率属于玄学前期用硬件选型把不确定性压下来比后期反复补卡划算。2.2 NDEF写入格式一条URL记录的正确姿势NFC芯片本身只是一块存储能被手机读取并触发跳转靠的是NDEF标准。碰一碰场景写的是NDEF URI记录记录头部包含TNF类型名格式、类型长度、载荷长度实际载荷就是你要跳转的完整URL。这一步常见的翻车点是写入时把URL截断或者带了不可见字符导致读取后跳转到一个无效地址。批量写卡我一般用PN532读卡器配nfcpy脚本现场写一批一张几秒钟比拿手机App逐张按高效得多。脚本核心只有几行import nfc clf nfc.ContactlessFrontend(usb) # 连接PN532读卡器 def write_url(tag, url): from nfc.ndef import UriRecord record UriRecord(url) # 构造NDEF URI记录 tag.ndef.message record # 写入标签NDEF区 URL https://yourdomain.com/landing?cid1001batchB2024 while True: tag clf.connect(rdwr{on-connect: lambda tag: write_url(tag, URL)})这段脚本的逻辑是连接读卡器把目标URL封装成UriRecord对象再写入标签的NDEF消息区。需要注意两点一是写卡前确认标签没被写保护二手卡先用tag.ndef.message None清空原数据再写二是URL必须带https://协议头不能省略否则部分手机读取后无法识别协议类型直接不响应。实际投放时URL里的cid和batch两个参数要提前规划好分别对应卡片编号与投放批次方便后台做数据分组。2.3 三条跳转路径微信直达、H5中转与浏览器兜底标签能读出来之后下一个决策是跳转到哪里。这里有三条主流路径。路径A微信直达Android微信支持在NFC标签里写入微信约定格式的链接用户碰卡后在微信内直接拉起对应的小程序页面。优点是路径最短缺点是需要按微信的约定格式拼接而且iOS上基本不生效——苹果对NFC标签拉起第三方App限制得很死。路径BH5中转标签里写一个普通HTTPS落地页地址碰一碰后打开浏览器或微信内置浏览器页面再通过微信开放标签能力把用户带进小程序。优点是双端兼容缺点是比直达多一步加载。同城拓客系统源码默认按这条路径实现H5落地页会带上卡片参数判断当前环境后决定直接进小程序还是先渲染网页。路径C浏览器兜底标签写商家官网或纯H5页面不强行进小程序适合本身没有小程序、只想用碰一碰做品牌展示的场景。实战里路径B是性价比最高的选择兼容性最好。落地页URL的格式一般是https://yourdomain.com/landing?cid1001batchB2024H5页面读取参数后在微信内置浏览器里拉起小程序路径pages/landing/index?cid1001batchB2024参数原样透传。2.4 系统角色与数据流三个端口各有分工搞清楚硬件链路后再看系统本身。这套拓客源码包含三个角色用户端是微信小程序碰卡后进入看到商家主页、活动页面或领券入口商家端管理自己的卡片查看访问和线索数据平台端是所有商家的管理中心负责卡片批次、渠道分配和全局统计。数据流方向是NFC标签参数 → 小程序落地页 → 后端记录访问日志 → 商家与平台后台查询分析。有一点在源码里要重点确认商家端和平台端的数据隔离是在后端接口层做的不是靠前端隐藏按钮。卡片表里必须有merchant_id字段后端查询接口强制带上商家ID作为过滤条件否则一个商家改一下请求参数就能看到全平台数据这个漏洞在带多商家的源码里很常见。拿到源码后先检查所有列表接口是否都做了这层隔离。3. 核心模块拆解小程序落地页、后端接口与数据库设计3.1 小程序落地页渠道参数读取与访问上报小程序端是整个链路的用户第一触点。碰卡跳进小程序后落地页要做三件事读取URL上的渠道参数、渲染商家内容、提示用户授权手机号。渠道参数在跳转时通过小程序页面路径的query传进来落地页在onLoad里统一接收。// pages/landing/index.js Page({ data: { cid: , batch: , merchantInfo: null }, onLoad(options) { // 从页面路径读取渠道参数 const cid options.cid || ; const batch options.batch || ; this.setData({ cid, batch }); // 上报访问记录不阻塞界面渲染 this.reportVisit(cid, batch); // 根据卡片ID拉取商家信息 this.loadMerchant(cid); }, reportVisit(cid, batch) { wx.request({ url: ${API_BASE}/api/visit, method: POST, data: { cid, batch, source: nfc }, success: () {}, fail: () { // 上报失败时缓存到本地下次打开补报 const pending wx.getStorageSync(pending_visits) || []; pending.push({ cid, batch, time: Date.now() }); wx.setStorageSync(pending_visits, pending); } }); } })这段代码的关键逻辑是访问上报做成非阻塞请求不因为网络慢卡住页面展示上报失败不直接丢而是存本地缓存后续打开再补报。这样后台统计不会因为弱网环境掉数据。参数cid是卡片编号batch是投放批次source固定传nfc用于和扫码来源做数据区分方便后期对比两种渠道的转化差异。授权手机号是留资的核心动作。微信小程序的手机号验证组件能自动填入手机号但要求企业主体且完成认证。个体户或个人主体小程序的开发者源码里要保留手动输入手机号的兜底表单避免用户被卡在授权这一步流失。两种方式建议同时保留用户拒绝快速验证时还能手动填。3.2 后端接口设计访问日志、线索回传与防重后端部分源码提供了一套REST接口核心两个访问上报接口和线索提交接口。访问上报在用户进入落地页时调用记录卡片、openid、时间、IP线索提交在用户授权手机号后调用写入线索表并标记来源渠道。接口参数设计可以参照这张表接口方法入参说明/api/visitPOSTcid, batch, openid, source记录一次访问/api/leadPOSTcid, openid, phone授权手机号后提交线索/api/card/listGETmerchant_id, page商家端卡片列表/api/stats/trendGETmerchant_id, batch, date_range访问趋势统计这里最容易出错的是重复上报用户进入页面一次授权前又刷新一次如果不做去重后台数据会虚高。源码里通常按“同一openid在60秒内对同一卡片的重复上报只记一次”过滤。实现上不需要建额外表用Redis以openid:cid为key存一条带过期时间的记录就行过期前再次请求直接返回成功但不写日志。3.3 数据库表卡片表、访问表、线索表怎么建数据库设计决定了后续数据复盘的上限。同城拓客系统最少需要三张核心表卡片表、访问日志表、线索表。我一般这样建-- 卡片表每张物理卡一条记录 CREATE TABLE nfc_card ( id int(11) NOT NULL AUTO_INCREMENT, card_sn varchar(32) NOT NULL COMMENT 卡片序列号, batch_id varchar(32) NOT NULL COMMENT 所属批次, merchant_id int(11) NOT NULL COMMENT 所属商家, status tinyint(1) DEFAULT 1 COMMENT 1启用 0停用, created_at datetime DEFAULT NULL, PRIMARY KEY (id), KEY idx_merchant (merchant_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 访问日志表每次碰一碰进入留痕 CREATE TABLE nfc_visit_log ( id int(11) NOT NULL AUTO_INCREMENT, card_sn varchar(32) NOT NULL, openid varchar(64) DEFAULT NULL, ip varchar(64) DEFAULT NULL, visit_time datetime DEFAULT NULL, PRIMARY KEY (id), KEY idx_card_time (card_sn, visit_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 线索表授权手机号后写入 CREATE TABLE nfc_lead ( id int(11) NOT NULL AUTO_INCREMENT, card_sn varchar(32) NOT NULL, openid varchar(64) NOT NULL, phone varchar(20) DEFAULT NULL, status tinyint(1) DEFAULT 0 COMMENT 0未跟进 1已跟进 2已成交, created_at datetime DEFAULT NULL, PRIMARY KEY (id), KEY idx_card (card_sn) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这三张表的设计要点card_sn关联物理卡让每一条线索都能追溯回具体是哪张卡带来的访问日志表的联合索引(card_sn, visit_time)优先支撑时间范围查询因为商家日常看的最多的就是“某个时间段内某张卡的访问趋势”线索表不直接存渠道名称而是通过card_sn反查卡片表再关联到批次避免渠道改名后历史数据失效。3.4 商家后台与平台端权限隔离和批量操作后台部分源码一般是Web管理界面。商家端能看到自己的卡片、自己的访问数据、自己的线索平台端能看到全部。权限隔离的常见做法是后端从登录态里解析出merchant_id列表接口查询时强制拼接这个条件而不是只靠前端隐藏入口。批量操作这块要关注是否能按批次生成待写URL的CSV导出。比如要投放一个商场一次注册100张卡后台一键导出100条带cid参数的URL写卡脚本按CSV逐行写入标签。如果源码没有这个功能二次开发成本也不高就是查表拼字符串再写CSV。4. 部署与排查从源码到上线五个高频坑4.1 部署前准备域名、HTTPS、服务器与小程序部署这套系统前先把环境清单列出来一个已备案域名、一张HTTPS证书、一台能跑Nginx和MySQL的服务器、一个已认证的小程序账号。没有HTTPS的话NFC落地页在微信内置浏览器里会被拦截这是部署碰一碰项目最常见的一个前置坑。如果小团队起步不用专门买高配服务器2核4G的普通配置跑这套系统完全够用因为NFC碰一碰的并发特点是“低频突发”单个商家单日访问量很难高过扫码场景瓶颈通常在物料投放数量而不是服务器性能。4.2 部署步骤从配置文件到第一张卡跑通拿到源码包后按顺序执行这几步每一步之间都有依赖不要先写卡再配环境创建数据库并导入SQL脚本确认nfc_card、nfc_visit_log、nfc_lead三张表创建成功修改后端配置文件的数据库连接串确认服务器能连上MySQL启动后端服务用curl请求/api/visit接口验证返回正常配置Nginx反代和HTTPS证书浏览器访问https://你的域名/landing?cidtest修改小程序代码里的API_BASE为你的HTTPS域名上传体验版用写卡工具写入落地页URL手机碰卡测试完整链路Nginx反向代理的配置可以参考这一段server { listen 443 ssl; server_name yourdomain.com; ssl_certificate /etc/nginx/cert/fullchain.pem; ssl_certificate_key /etc/nginx/cert/privkey.pem; location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location / { root /var/www/nfc-landing; index index.html; } }这段配置把后端接口/api/反向代理到本地8080端口静态页面直接走文件目录。注意proxy_set_header两行不能省否则后端拿不到用户真实IP访问日志里的IP字段会全部变成Nginx所在的内网地址后续做门店地域分析时就废了。4.3 避坑记录五个高频问题坑一Android碰卡没反应后台也没有访问记录现象手机贴上去后没有任何弹窗后台日志查不到这条访问。 原因标签里写的URL不是完整HTTPS地址或者写入时带入了不可见字符也可能手机系统NFC功能没开启。 解决先用NFC读取工具读一遍标签内容确认URL完整且带https://协议头然后在手机设置里把NFC开关打开部分国产机还需要在“更多连接”里单独开启读卡模式再测试。坑二iOS碰卡无法直接进小程序现象苹果手机贴卡后弹出Safari或者系统跳转提示就是进不到微信小程序。 原因iOS对NFC标签拉起App的限制微信在iPhone上对直接跳小程序的支持不完整。 解决标签里写H5中转落地页页面里做微信环境判断检测到微信内置浏览器时再拉起小程序非微信环境就展示网页版内容。这也是源码默认走H5中转的原因。坑三手机号授权组件拿不到完整手机号现象用户点了授权后台存到的手机号全是星号或空值。 原因小程序用了旧版手机号授权接口新版基础库要求企业主体且需在小程序后台申请能力个人主体直接被限制。 解决确认小程序是企业主体且已认证配置好报备的手机号解密密钥如果主体不符合保留手动输入手机号的兜底表单不要只依赖一键授权。坑四后台统计的访问量明显低于实际触碰量现象投放一周后台显示访问次数只有实际投放触碰的不到一半。 原因一部分用户碰了卡但没有确认跳转或者落地页上报接口在弱网下失败后直接丢弃。 解决小程序端加上失败缓存补报机制就是3.1代码里的pending_visits逻辑后台把“触碰-打开-授权”三个阶段的数据分开展示避免口径混在一起比较。坑五小程序提审时核心功能无法体验现象提审被驳回理由是核心功能无法完整体验或要求提供演示录屏。 原因审核人员手里没有NFC卡片硬件无法走真实的碰一碰流程。 解决源码里预留一个“模拟碰一碰”入口输入卡片编号即可进入落地页提审时以这个入口演示完整链路。这个入口建议只在审核版开启正式版隐藏避免用户绕过NFC直接输入编号破坏渠道追踪的准确性。5. 进阶玩法渠道参数验证与批量投放复盘投放不是把卡发出去就结束了验证才是真正拉开效果差距的环节。我的习惯做法是每个门店用一个独立批次号比如某商场B1层是B2024AB2层是B2024B卡片上同时印出批次编号。投放一周后导出后台数据按批次对比访问量、授权率、线索转化率。某次投放就出现过这样的反差A点访问200次、授权35条B点访问80次、授权却也有35条。访问量差两倍多授权数一样说明差距根本不在渠道位置而在落地页内容和店员引导话术这时候要优化的是页面利益点而不是加印卡片。这个资源里还有一个容易被忽略的用法NTAG215卡片可以反复写入。测试阶段把同一张卡通过批量脚本改写URL参数就能模拟不同门店、不同渠道的投放效果一套卡当三套卡用物料成本省下来不少。批量改写时注意顺序先读卡清空再写入新URL避免旧参数残留导致后台数据串批次。从那以后我给自己定了个规矩任何一次NFC碰一碰投放上线前必须拿一台Android和一台iPhone实测完整链路再检查后台访问日志里能不能查到这条记录。两步走完后面基本不会再出大的幺蛾子。希望帮到你。本文还有配套的精品资源点击获取