前言
最近"死了么"这款 App 因为精准切入独居人群的安全痛点而爆火。截止到今天已经攀升到苹果付费App排行榜第一的位置了!

它的核心逻辑非常简单: "签到保平安,断签发邮件" 。
出于好奇,我去了解了相关信息,看到一个数据,据第七次全国人口普查数据显示,我国一人户家庭已超1.25亿户,占全国户口总数的25%。对于独居人群来说,发生意外不可怕,可怕的是无人知晓,这款APP也是精准踩中了这部分人的痛点。
于是,我连夜敲代码,搞出了这款对标产品------ "活着呢"(TO BE LIVE) 。
产品哲学
它的逻辑极其简单粗暴:
- 生存契约:你设定一个"确认周期"(默认 48 小时)。
- 打卡续命 :在倒计时结束前,你必须上来点一下那个 "我还活着呢" 的按钮。
- 失联预警:如果你超时未点,系统将判定你"可能挂了",立即触发预警,通知你的紧急联系人。
技术选型
- 前端框架 :Next.js 14 (App Router)。极致的 SEO 和路由体验。
- 状态动效 :Framer Motion。让倒计时和按钮带上"呼吸感"。
- 后端支撑 :Supabase (BaaS)。无需自己写 CRUD,秒级实现 Auth 授权和数据库存储。
- 通知 :Resend。定时发送邮件。
- 主题适配 :Tailwind CSS。支持"深邃绿"与"荧光绿"的双重主题,白天是深沉的翡翠,深夜是守护的微光。
- 部署环境 :Vercel。全球加速,毕竟生命经不起等待。
核心代码实现
核心功能
- 注册/登录、退出
- 签到、紧急联系人设置
- 主题切换
登录页
在用户未注册时,可以先注册账号,再登录,核心代码如下:
js
const handleSubmit = async (e) => {
e.preventDefault()
setLoading(true)
try {
if (isLogin) {
const { error } = await supabase.auth.signInWithPassword({ email, password })
if (error) throw error
router.push('/')
} else {
const { error } = await supabase.auth.signUp({ email, password })
if (error) throw error
alert('验证邮件已发送,请查收!')
}
} catch (err) {
alert(err.message)
} finally {
setLoading(false)
}
}
签到页
最核心的功能是那个动态倒计时逻辑。我们需要在客户端实时计算剩余时间,并根据紧迫程度变换颜色。这里的安全周期是设定死的48小时,后期可让用户自定义。
js
<motion.button
whileTap={{ scale: 0.94 }}
onClick={handleCheckIn}
className="absolute inset-4 rounded-[4.5rem] bg-app-card border border-app-border flex flex-col items-center justify-center
shadow-[0_15px_40px_rgba(0,0,0,0.04)] dark:shadow-none"
>
<div className={`mb-4 transition-colors duration-1000 ${getAlertColorClass()}`}>
{timeLeft.h < 8 ? (
<AlertTriangle size={60} />
) : (
<Shield
size={60}
fill="currentColor"
fillOpacity={0.12}
className="drop-shadow-[0_4px_12px_rgba(0,0,0,0.05)] dark:drop-shadow-none"
/>
)}
</div>
<span className="text-2xl font-black tracking-tight text-app-text">我还活着</span>
<div className="mt-2 font-mono text-[11px] opacity-40 flex items-center gap-1.5 tracking-widest">
<Clock size={12} strokeWidth={2.5} />
{String(timeLeft.h).padStart(2, "0")}:
{String(timeLeft.m).padStart(2, "0")}:
{String(timeLeft.s).padStart(2, "0")}
</div>
</motion.button>
js
// 动态获取当前的强调色(预警系统)
const getAlertColorClass = () => {
if (timeLeft.h < 8) return "text-red-500";
if (timeLeft.h < 24) return "text-amber-500";
return "text-app-accent"; // 使用主题定义的强调色
};
const updateCountdown = useCallback(() => {
if (!profile?.last_check_in) return;
const last = new Date(profile.last_check_in).getTime();
const now = new Date().getTime();
const total = 48 * 60 * 60 * 1000;
const remaining = Math.max(0, total - (now - last));
setTimeLeft({
h: Math.floor(remaining / (1000 * 60 * 60)),
m: Math.floor((remaining % (1000 * 60 * 60)) / (1000 * 60)),
s: Math.floor((remaining % (1000 * 60)) / 1000),
percent: (remaining / total) * 100
});
}, [profile]);
useEffect(() => {
const timer = setInterval(updateCountdown, 1000);
return () => clearInterval(timer);
}, [updateCountdown]);
const handleCheckIn = async () => {
if (!user) return;
const now = new Date().toISOString();
const { error } = await supabase.from("profiles").update({ last_check_in: now }).eq("id", user.id);
if (!error) {
setProfile((prev) => ({ ...prev, last_check_in: now }));
if ("vibrate" in navigator) navigator.vibrate([50, 30, 50]);
}
};
PWA 改造:从网页变成桌面 App
作为一个守护工具,它必须触手可及。我为它集成了 PWA 功能,用户可以"一键添加到桌面"。
通过配置 manifest.json,我们的 App 实现了:
- Standalone 模式:隐藏浏览器地址栏,全屏沉浸体验。
- 自定义图标:一个可爱鬼(代表此时的你)和一颗回答"YES"的小心脏。

后记
"我还活着呢"(TO BE LIVE),在每一个平凡的 24 小时里,温柔地问一句: "嘿,还在吗?"
项目已开源/部署,欢迎大家来"续命"!
互动环节
如果你失联了,你最希望 App 给你的联系人发送哪句话? A. 帮我格式化手机,谢谢。 B. 我在异世界开挂了,莫念。 C. 救命!我还能抢救一下!