Appearance
不做GPS也能同城匹配?IP定位的「附近的人」玩法
做社交、本地生活类产品,绕不开"同城"两个字。用户没开GPS的时候怎么办?总不能啥都不显示吧。其实有个成熟的办法:用IP定位兜底,做个"模糊同城"。
这篇讲讲思路,以及我踩过的坑。
为什么需要IP定位兜底
做过社交App的都知道,很多用户是不愿意开定位权限的(怕被关联、怕耗电)。但"同城推荐"又确实有需求。
这时候IP归属地就派上用场了:
- 用户开了GPS:用高精度定位;
- 用户没开GPS:用IP归属地做个"城市级"匹配,虽然没那么准,但至少能把同城的圈子转起来。
很多平台的做法是"IP做默认,GPS做增强"。
核心实现:怎么算"同城"
思路很简单,三步:
- 查用户IP归属地,拿到城市;
- 把城市作为用户的一个标签存起来;
- 匹配时,相同城市的用户互相可见。
python
# 查询用户IP归属地
def get_user_city(ip):
info = query_ip(ip) # 查IP9
if not info:
return None
# 国内用"省+市"作为同城key
if info.get("country") == "中国" and info.get("city"):
return f"{info['prov']}-{info['city']}"
# 海外用国家
return info.get("country")存的时候,把城市ID写进用户表,检索时直接 WHERE city = ? 就能拉到同城用户。
更聪明一点:用经纬度做半径匹配
IP9 返回里有 lng、lat(城市中心坐标)。可以基于这个做"半径"逻辑,比死板的"同城"更灵活:
python
import math
def distance(lat1, lng1, lat2, lng2):
# 简化的球面距离
R = 6371
p1, p2 = math.radians(lat1), math.radians(lat2)
dp = p2 - p1
dl = math.radians(lng2 - lng1)
a = math.sin(dp/2)**2 + math.cos(p1)*math.cos(p2)*math.sin(dl/2)**2
return 2 * R * math.asin(math.sqrt(a))注意:IP给的经纬度是城市中心点,用它算距离会得到"A用户的城市中心距B用户的城市中心多远"。这对同城匹配够用了,但别当成两个人的真实距离。
排序策略
匹配出来的"附近的人",排序别太死板。我建议加权:
- 开了GPS的用户,按真实距离排;
- 没开GPS的,用IP城市匹配,但排在后半段;
- 别把"同城"变成唯一标准,结合活跃度、兴趣等一起排。
我踩过的坑
坑1:移动用户IP乱跳。 前面说过,手机流量IP经常飘。结果就是用户昨天还是"北京",今天就变"廊坊"。解决:城市标签不要天天更新,缓存个3~7天,稳定第一。
坑2:基站IP查不准。 蜂窝网络的IPv4出口IP集中在省会,小城市用户会被误判到省会。解决:优先查IPv6,准确性会高不少(IP9支持)。
坑3:海外用户显示"未知"。 只处理了国内城市,忘了海外。记得海外兜底用国家,至少别让人看到空白。
隐私红线
用IP做同城推荐,一定要克制:
- 只展示到"城市级",不要展示用户精确位置;
- IP数据别拿来"精确定位用户",用户会反感;
- 给用户提供关闭同城/位置功能的开关。
说点实在的
IP定位的同城,体验上肯定不如GPS精确,但胜在零门槛、免授权。对很多产品来说,"先把同城跑起来"比"同城精确到百米"更重要。先用IP兜底把冷启动做了,等用户量上来,再引导他们开GPS提精度,这是很顺的路径。