在北京的深夜里，交接我的生活与逻辑
01 燃料窗外是 2026 年初的北京，望京的灯火依旧像是一台永不宕机的服务器阵列。我就坐在这阵列的一个节点上，耳机里是降噪模式开启后的静谧，指尖下是机械键盘沉闷的敲击声。我的日常被那些琐碎而庞杂的指令填满：去跳板机申请权限、给十几年前的陈旧 Bug 打补丁、在各种毫无意义的周报缝隙里寻找系统的喘息。在宏大的架构面前，我那些所谓的“代码审美”显得如此微不足道，甚至有些滑稽。我曾听人描述过一种状态：劳动者与他所创造的对象逐渐变得陌生，甚至对立。以前我不懂，现在我明白了。我每日亲手构建的那些逻辑，并不属于我，我甚至无法从心底认可它们的价值。我就像个在流水线旁拧螺丝的工人，只不过我的螺丝是 Shell 脚本和 YAML 文件。我敲下的每一行字符，并非我灵魂的延伸，而仅仅是维持这台庞大机器继续空转的燃料。02 赎金常有人轻巧地建议：“如果不快乐，换个地方就是了。”这种轻巧往往源于一种幸运，即身后始终有一条退路。但我知道，我身后并没有那个可以被称为“避风港”的地方。老家那个小城是我拼命想要逃离的源头，那里藏着长达十八年的压抑和寒冬。如果我此刻因为任性而撤退，瞬间就会被那股熟悉的寒意重新包裹。靠着这份并不热爱的职业，我才终于在这座城市里扎下了根。这种独立是具体而昂贵的，它标价在每月初准时发来的水电账单里，折算在深夜下班后那一碗热腾腾的泡面里。我没有那种“说走就走”的潇洒，那更像是一种昂贵的幻觉。这些枯燥的开销，其实是我支付给生活的赎金。于是，我必须忍受这份“为他人作嫁衣”的损耗。那些机械的指令、违心的社交、以及毫无意义的评审，都是我为了守住这间出租屋所必须付出的代价。每当深夜回屋，我关上那扇属于自己的房门，听着门外的喧嚣被隔绝，那一刻的寂静，才是我在这座庞大城市里唯一真正拥有的领地。03 氧气我曾在深夜关闭公司的 VPN，看着终端光标在黑暗中机械地闪烁，感到一种巨大的空洞。起初，我以为我只是厌恶加班。但后来我发现，当我在自建的 NAS 上，为了调通一个协议而反复折腾到凌晨三点，甚至在终于看到那个“Login Success”的跳转界面而感到心跳加速时，我才意识到：我并不疲惫，我只是在窒息。我需要氧气。我开始沉迷开源社区。在那里，逻辑是唯一的度量衡。一个 PR 的通过与否，取决于它的优雅与效率，而非提词人的职级，更没有职场里那些弯弯绕绕的委婉语。在那里，我不是一个被雇佣的“人力资源”，而是一个拥有主体性的、正在构建什么的个体。在工位上的每一小时，我都在支付我的生命去充实别人的资产，那是为了生存而进行的“抵押”。而当我为了自用服务写下代码时，我才重新拥有了我自己的东西。那是我的 commit，那是我的逻辑。我不再是传送带上的影子，我是一个正在延伸自己灵魂的创造者。这种追求甚至与金钱无关，它关乎一种最朴素的尊严：我希望我的创造物，是因为它本身值得存在，而不是因为它能填补某张 KPI 表格的空白。04 潜伏现在的我，依然会因为通讯软件里跳出的消息头像而感到一阵生理性的心悸。每一次被迫在工位上打起精神进行的社交，都像是在进行一场漫长的潜水，水面下是让人窒息的虚妄。但我学会在心里划出一道界限。一边，是必须要支付给现实的劳动力。那是从早上十点到晚上九点的枯燥循环，是为了换取生存资源而不得不处理的业务逻辑；而另一边，是我深夜在键盘上敲下的代码，是那些在开源世界里诚实跳动的字符。只有在那个时候，我才觉得我是一个完整的人。我并没有摔门而去的果敢。那种对“回到过去”的恐惧，盖过了对现状的厌恶。所以，我选择潜伏。我试着在厌倦的任务里，偷偷打磨自己的技术；在深夜的寂静里，一分一秒地存下属于我的时间。这并不是什么励志的进取，而是一种极其卑微的囤积。我希望这些存下的东西——无论是技术还是那点微薄的积蓄——终有一天能变成一份足够重的筹码。让我能在这个被效率和金钱锁死的缝隙里，买回一点点支配自己生命的权力。我已经在荒原上建立了自己的观测站。虽然现在的空气依然稀薄且寒冷，但我知道，只要电费还在交，只要代码还在跑，我就依然拥有我的独立王国。这也许就是成长的代价：得先学会忍受荒诞，才能最终走向纯粹。
身体是一座钟摆，悬挂在城市这座巨大而精密的时钟上。摆动轨迹被设定得无可挑剔：一端是被称为“家”的充电接口，另一端是名为“公司”的能量消耗器。每日准时划过一道弧线，在清晨的死寂与深夜的疲惫之间，精准，重复，毫无新意。钟摆的灵魂常常漂浮在躯壳之外，冷眼旁观。看着它汇入地铁的铁皮洪流，被压缩成罐头里沉默的鱼；看着它坐在泛着幽蓝光芒的屏幕前，手指像被驯化的蜘蛛，在键盘上编织着一张张名为“价值”的网；看着它在会议室里点头，在工作群里回复“收到”，表情是一张从社会面具店里批发来的、最标准耐用的款式。他们说，这就是所谓“大人”的世界。二十三岁，身份证上的出生日期说明了这样的数字，那是一个在法律与社会学意义上都无可辩驳的成年数字。可总是觉得，灵魂还在童年那片长满狗尾巴草的荒地里迷了路。它不认识这具西装革履的钟摆，不明白为什么日出不再是冒险的号角，而成了催命的闹铃。我，究竟在渴望什么？渴望在太阳刺破地平线的第一秒，就用皮肤去迎接那缕金色的、带着露水凉意的光。渴望光线穿透身体，把所有沉积在骨骼里的、名为“KPI”和“DDL”的阴影都驱逐干净。渴望听见的不是地铁报站的机械女声，而是林子里第一声清脆的鸟鸣，那声音诉说着世界的苏醒，也唤醒沉睡的感知。渴望赤脚走在溪边的石头上，让冰凉的流水亲吻脚踝，把那些名为“人情世故”的淤泥都冲刷而去。渴望躺在草地上，不是为了午休片刻的苟延残喘，而是为了看一朵云从山的一头飘到另一头，看它如何聚拢，又如何消散，就这么无所事事地，挥霍掉一个完整的下午。渴望风，那个自由的、不羁的流浪汉，来阅读掌心的纹路，而不是让打卡机来定义一天的开始和结束。然而讽刺的是，每天清晨，最先唤醒一切的，是那套“大人”的逻辑。它冷静地宣告：那些山川、河流、清风、朗月，是一场昂贵的梦。而眼前的这份两点一线，这份可预见的疲惫，才是能换取面包和庇护所的、最“划算”的交易。于是心甘情愿地，或者说麻木地，将那个还在荒地里迷路的孩子锁得更深，然后操纵着这具钟摆，再次投入巨大的时钟，成为它永恒运转里和谐，却毫无声响的一部分。出卖了清晨，出卖了黄昏，出卖了好奇心和野性，换来一个“社会人”的身份。学会了如何像成年人一样谈论天气、薪水和未来的房价，却忘了该如何好好地爱那个疲惫不堪的自己。生活成了一张密密麻麻的待办清单，完成了所有任务，却唯独忘了“享受”那一项。有时，在深夜，当钟摆终于停歇，透过窗户玻璃的反光，能看到一张模糊的脸。二十三岁，写满了不属于这个年纪的倦意。总觉得那不是真实的自己，只是一个名为“我”的角色，在这场盛大的、名为“生活”的舞台剧里，随波逐流的群众演员。而真正的灵魂，还在那片荒地上，等着一场永远不会到来的日出，向往着一片从未抵达过的远方。
黎明前的城市弥漫着一种虚伪的宁静。路灯还在尽职地亮着，在潮湿的柏油路上投下一个个昏黄的光晕，像被随手丢弃的橘子皮。我从被雨水泡软又晒干的纸箱里钻出来，这个曾经装着"尊贵版32寸液晶电视"的纸箱如今成了我的寝宫，边角还留着上个住户，一只暴躁的灰老鼠啃咬的痕迹。伸懒腰时，左后腿那道被自行车轮辐留下的旧伤开始隐隐作痛，让本该优雅的动作变成了一个踉跄的滑稽舞步。晨风送来远处面包店的第一炉香气，混着巷子里特有的味道——腐烂的菜叶、变质的牛奶，以及永远挥之不去的尿骚味。三个并排的垃圾箱在渐亮的天光中闪烁着冷冰冰的金属光泽，箱壁上黏着可疑的污渍和几根来历不明的毛发。最右边那个箱盖永远合不拢，像人类咧开的、缺了门牙的嘴。"又一个充满希望的早晨。"我舔了舔前爪，舌尖掠过昨天在争夺半根香肠时留下的伤口。胃里传来熟悉的绞痛，像是有人用生锈的钢丝在里面翻搅。人类总爱说我们猫有九条命，但他们从不说这九条命都得用来数垃圾箱里的鱼骨头，用来计算便利店老板挥舞扫把的角度，用来记住哪条巷子的醉汉会突然飞起一脚。我的胡须颤动了一下，捕捉到空气中飘来的一丝鱼腥味——是时候开始今天的觅食表演了。第一站是后巷那家"甜蜜时光"面包店的垃圾箱。我贴着墙根潜行，脏兮兮的姜黄色皮毛与斑驳的砖墙融为一体，只有尾巴尖那撮白毛像个不听话的叛徒，在晨光中轻轻晃动。后腿肌肉绷紧，一个利落的起跳——我精准地落在垃圾箱边缘生锈的铁框上，肉垫与金属接触时发出轻微的"嗒"声。这套动作我重复了三百二十七个清晨，熟练得就像歌剧院里跳《天鹅湖》的芭蕾舞者，只不过我的舞台是油腻的垃圾箱，观众是几只正在翻找早餐的蟑螂。箱内的景象让我的耳朵失望地耷拉下来：几个被揉成团的面包袋可怜巴巴地躺在底部，人造奶油从破口处渗出，在塑料袋上凝结成恶心的黄色痂块。更可气的是，每个袋子都被咬开了整齐的缺口——夜班的老鼠们连面包屑都没给我留。我伸出前爪，钩爪从磨损的肉垫中弹出，嫌弃地拨弄着那些沾满齿痕的塑料袋。甜腻的香精气味窜入鼻腔，突然唤醒某个遥远的记忆：曾经有双温暖的手把我抱在膝头，指尖带着同样的甜腻味道。我甩了甩头，左耳的缺口随着动作轻轻颤动——多么讽刺啊，连最美好的回忆都裹着垃圾的腐臭。"滚开，脏东西！"后门猛地撞开，一个系着沾满面粉的褐色围裙的男人冲了出来。他挥舞扫把的动作活像中风的老狗在追自己的尾巴。我的身体在他第一个音节出口时就已经做出了反应——后腿在垃圾箱边缘一蹬，前爪精准抓住防火梯生锈的栏杆，整个身体在空中划出一道完美的弧线。等我蹲在二楼平台上时，他的扫把才"砰"地砸在我刚才站立的位置。居高临下望去，那个男人涨红的脸活像面包房里没烤熟的菠萝包。他仰着头骂骂咧咧，唾沫星子在晨光中闪闪发亮："该死的野猫！传播病菌的瘟神！"我慢条斯理地舔了舔前爪，突然觉得很好笑——至少我不必像他一样，每天凌晨三点起床，把廉价的人造奶油抹在更廉价的面包上，还要对着挑剔的顾客挤出笑脸。阳光照在我残缺的左耳上，那里已经结痂的伤口又开始隐隐作痒。转战第三个垃圾箱时，运气终于眷顾了我。半块被雨水泡发的披萨，虽然上面的菠萝已经发酸，但火腿依然保持着某种倔强的美味。我叼着战利品躲到空调外机后面，一边吃一边警惕地环顾四周。在这里，每口食物都可能用尊严换来，而保住它的代价往往是几道新鲜的抓痕。午后的阳光像融化的黄油铺在柏油路上。我蹲在便利店门口，盯着柜台里那个穿校服的女孩。她已经连续三天在这个时间买火腿肠了，而且总会"不小心"掉一小截在地上。人类总以为自己很聪明，其实他们的怜悯心就像廉价火腿肠的保质期一样短暂而虚伪。"小猫咪..."她蹲下来时，校服裙摆蹭到了地上的灰尘。她刻意眯起眼睛，嘴角扬起一个练习过太多次的弧度——那种人类专门用来对着镜子训练的"可爱笑容"。声音甜得像是融化的棉花糖，黏糊糊地裹着某种期待。我的尾巴尖抽动了一下，在水泥地上拍出轻微的声响。这个距离足够安全，正好在她手臂长度之外，又不会远到让她放弃尝试。女孩涂着透明指甲油的手指慢慢伸过来，我看到她修剪整齐的指甲边缘还留着啃咬的痕迹。当我的后跳打破这个精心设计的温馨场景时，她脸上的肌肉出现了一系列微妙的变化：先是眼睛微微睁大，嘴角的弧度僵住了，像被按了暂停键的动画片。然后那层甜腻的笑容像阳光下的冰淇淋一样慢慢融化，露出底下真实的失落。她的下唇无意识地撅起一瞬，又立刻被牙齿咬住。"真没劲。"这句话从她齿间挤出来时已经失去了所有温度。她站起来拍了拍裙子，动作刻意放得很重，仿佛这样就能挽回些面子。转身时，她马尾辫甩动的幅度比平时大了许多——人类总是这样，连生气都要用肢体语言再强调一遍。那截火腿肠被她故意留在原地，在阳光下渐渐渗出透明的油脂。我等到她的身影消失在街角才上前，叼起已经沾满灰尘的食物。尊严？那是有家可回的猫才配拥有的奢侈品。黄昏时分，我在幼儿园锈迹斑斑的铁栅栏外发现了一个奇迹——整条鲤鱼！它斜躺在排水沟边缘，鱼鳃还挂着几片蔫巴巴的葱花，显然是某个孩子午餐盒里的"营养配餐"被嫌弃后扔出来的。鱼身一侧沾着暗红色的酱汁，在夕阳下像凝固的血迹，另一侧已经被晒得泛白起皮。我正要用爪子拨弄这意外的馈赠，突然一阵窸窣声从冬青丛后传来。枯叶被踩碎的声响让我背上的毛瞬间炸开。只见一只虎斑猫慢悠悠地踱出阴影，他右耳缺了半截，肩胛骨在皮毛下隆起狰狞的弧度——是这片街区的"疤面煞星"。他琥珀色的瞳孔缩成两条细缝，胡须上还沾着上次斗殴留下的血痂。我们同时压低了身体，我的尾巴膨大成平时的两倍，他的尾巴则像响尾蛇般危险地左右摆动。他喉咙里滚动的呼噜声不是示好，而是生锈刀片互相摩擦的声响。当他的右前爪试探性地向前移动时，我左后腿的旧伤突然刺痛起来——上周就是在这里，他的利爪留下了那道还未痊愈的伤口。三秒钟的对峙像被拉长的橡皮筋。他故意露出犬齿时，我闻到了鱼腥味混着腐肉的气息。当他的肌肉开始绷紧准备扑击时，我的左后腿不争气地抽搐了一下。这个细微的破绽让他立刻发出胜利的呼哧声，尾巴得意地卷成问号形状。虎斑猫叼起战利品时故意让鱼尾扫过我的鼻尖，酱汁甩在我胡须上。我立刻低头舔爪子，装作对墙角突然出现的蚂蚁产生了浓厚兴趣，因为输家的尊严就是假装你本来就不想要。他的脚步声远去后，我才发现刚才太过用力，爪子已经把地面刨出了几道浅浅的痕迹。排水沟里，鱼形的油渍正在暮色中慢慢晕开。夜幕降临，城市换上了它光鲜亮丽的晚礼服。我穿梭在霓虹灯照不到的阴影里，寻找今晚的栖身之所。垃圾桶后面太潮湿，车底下有汽油味，那个总是喂猫的老太太的楼道又挤满了新来的流浪猫。最后我选中了一家关闭的店铺门口的纸箱，虽然有点小，但至少避风。正当我准备蜷缩进去时，一股熟悉的气味飘了过来。循着味道，我在一堆建筑垃圾后面发现了天堂——有人扔了一张单人床垫！虽然边角已经发霉，但中间部分依然柔软得令人想哭。更不可思议的是，床垫旁边还有个开了一半的猫罐头，虽然过期了，但密封的那部分依然散发着诱人的腥香。我谨慎地尝了一口，味蕾立刻绽放出烟花。这不是垃圾箱里那种带着施舍意味的残羹冷炙，这是专为猫准备的食物。我狼吞虎咽地吃完，连罐子都舔得能照出我脏兮兮的脸。吃饱喝足后，我跳上床垫，在上面转了三圈才找到最舒服的姿势躺下。抬头望去，城市的灯光太亮，看不见星星。但没关系，今晚的床垫就是我的银河，过期的猫罐头就是我的米其林大餐。"也许明天又得回到垃圾箱。"我迷迷糊糊地想，爪子不自觉地揉捏着发霉的床垫面料。但此刻，我是世界上最富有的猫。人类花大价钱买的猫爬架算什么？我的宫殿是城市丢弃的废物构成的，我的王冠是用警惕和伤痕换来的。在坠入梦乡前的最后一刻，我突然明白了为什么人类总说"幸福像猫一样"。因为他们永远不知道，对我来说，一个发霉的床垫和半罐过期食品，就足以构成一生的高光时刻。
我签下了那份合同，像签下一张卖身契。屏幕上的offer letter泛着冷光，HR的祝贺邮件里藏着无数个未言明的996。他们说这是福报，是千军万马挤独木桥后的胜者奖杯。可为什么我摸着键盘的手在发抖？四年前那个拖着行李箱的少年，站在校门口时还揣着些天真的幻想：要读海德格尔，要写诗，要躺在操场上数星星。如今他的简历上只剩下“精通多线程编程”“熟悉K8s集群部署”……多么体面的墓志铭啊。图书馆的旧书还翻在里尔克那页，而我的大脑早已被LeetCode题库腌渍入味。这世道多幽默。我们像一群被迫参加饥饿游戏的选手，却要假装热爱竞技。凌晨三点的自习室里，咖啡和红牛是新时代的圣餐；实习证明叠成阶梯，每一步都踩着同龄人的叹息。最可笑的是，我们管这叫“成长”——仿佛人的价值就该被换算成年包数字，灵魂活该塞进西二旗的早班地铁里发酵。工牌明天就会挂上我的脖子，那根蓝色挂绳真像条精致的绞索。我知道自己会学会对周报里的谎言面不改色，会习惯在深夜改需求时给外卖小哥打五星好评。但此刻请允许我，最后一次像个文艺青年那样矫情：我想要自由。不是调休拼凑的小长假，不是年假审批通过时的卑微狂喜。是敢于在春风里发呆一整天的自由，是拒绝用健康兑换期权时的自由，是承认“我不想卷了”的自由——像宿舍楼下那丛野蔷薇，从没人给它做OKR，它倒开得比所有KPI都漂亮。（明天起，我将成为光荣的牛马。但今晚，请让我为那个还没被驯服的自己，默哀三分钟。）
GC 和 Full GC 的定义GC（Garbage Collection，垃圾回收）是JVM自动管理内存的一种机制，用来回收不再使用的对象所占用的内存空间。JVM的垃圾回收机制主要分为两种：Minor GC 和 Full GC。Minor GC：主要回收 新生代（Young Generation）中的对象。它通常发生在新生代的空间不足时，频率较高。回收后，新生代的空间得到释放，一部分存活的对象会晋升到老年代。Full GC（或 Major GC）：回收整个 堆内存（包括新生代和老年代），通常在老年代空间不足时发生。Full GC 的过程更为耗时，因为它需要回收老年代中的对象，并且涉及到整个堆的扫描。Full GC 发生时出现的现象Full GC 发生时，通常会出现以下现象：应用程序暂停（Stop-the-world）：Full GC 期间，JVM 会暂停应用程序的执行，直到回收完成。暂停时间通常较长，尤其是堆内存较大的时候，可能导致明显的延迟。内存占用波动：Full GC 可能会使应用程序的内存占用发生剧烈波动，因为整个堆内存都会进行回收。性能下降：由于Full GC通常需要较长时间进行内存回收，这会导致应用的响应时间增加，系统性能下降。GC日志中出现大量 Full GC 记录：可以通过查看GC日志发现频繁的 Full GC，可能是一个潜在的性能问题。如何解决 Full GC 的问题增大老年代（Old Generation）内存：如果老年代空间不足，可以通过增大堆内存中的老年代部分来避免 Full GC。参数设置：-Xmx<size>：设置堆的最大大小。-Xms<size>：设置堆的初始大小。-XX:NewRatio=<ratio>：调整新生代与老年代的大小比例。适当增大老年代的比例，减少老年代发生 Full GC 的可能性。-XX:MaxOldGen=<size>：直接设置老年代的最大大小。减少 Full GC 触发的频率:通过合理配置 晋升阈值（MaxTenuringThreshold）, 控制对象从新生代晋升到老年代的条件。如果对象在新生代中存活较长时间后才晋升，可以减少老年代的内存压力。参数设置：-XX:MaxTenuringThreshold=<value>：设置从新生代晋升到老年代的阈值。较高的阈值会让更多对象停留在新生代。优化对象的生命周期：检查是否有对象不必要地长时间存活于老年代，可以通过优化代码来减少不必要的对象创建。对于缓存、长时间存活的对象，考虑使用对象池或缓存清理策略。优化内存泄漏问题，确保无用对象能够及时被回收。选择合适的垃圾回收器:不同的垃圾回收器适合不同的场景。比如：G1 GC：适用于大内存应用，能够较好地平衡内存回收的停顿时间和吞吐量，避免长时间停顿。ZGC / Shenandoah：适用于对低延迟要求较高的应用，它们的设计目标是最小化停顿时间。CMS GC：适用于大多数需要较低延迟的应用，它会尽量避免停顿时间过长，但也容易引发 Full GC。Full GC 的原因老年代内存不足：最常见的原因是老年代（Old Gen）空间不足，导致无法分配新的对象或者无法回收足够的内存，触发 Full GC。持久的对象存活：如果某些对象在新生代中存活的时间较长，可能会频繁晋升到老年代，最终导致老年代内存不够。JVM 堆内存配置不当：堆内存的配置不合理，尤其是老年代空间设置过小，可能会导致 Full GC 频繁发生。内存泄漏：程序中存在内存泄漏，某些不再使用的对象仍然被引用，导致它们长时间存活并占用内存，最终触发 Full GC。垃圾回收策略不当：不恰当的垃圾回收器或配置，可能会导致老年代回收不充分，进而引发 Full GC。Old Gen（老年代）的定义什么是内存池 Memory Pool在JVM（Java虚拟机）中，内存池（Memory Pool）指的是JVM内存区域的划分。内存池主要分为堆内存和方法区，其中堆内存又被细分为多个区域，包括新生代（Young Generation）和老年代（Old Generation），以及一个特殊的区域——永久代（PermGen）或元空间（Metaspace），取决于JVM的版本。什么是老年代 Old Gen老年代（Old Generation）是堆内存的一部分，负责存储存活时间较长的对象。JVM的垃圾回收机制分为两大类：Minor GC和Major GC（有时称为Full GC）。在这其中：Minor GC：发生在新生代，主要回收的是新生代的内存。Major GC / Full GC：发生在整个堆内存（包括新生代和老年代），主要回收的是老年代的内存。当新生代中的对象经过多次垃圾回收后，如果它们仍然存活，它们会被转移到老年代中。老年代的对象通常是存活时间较长的对象，比如大部分的类实例和长期存活的数据。为什么需要区分老年代？性能优化：新生代通常发生较频繁的垃圾回收，而老年代的垃圾回收则较为稀少。因为新生代主要存储生命周期短的对象，垃圾回收更为频繁。而老年代则存储的是那些长时间存活的对象，不会频繁进行回收，回收频率较低。内存管理：老年代内存的管理相对复杂，因为如果老年代空间不足，可能会导致Full GC，这个过程通常比Minor GC更加耗时且影响性能。因此，合理的堆内存配置和垃圾回收策略对于性能至关重要。
使用ChromeOS优雅安装第三方APK写在开头然 ChromeOS 提供了一些官方的应用商店，但这些商店的应用数量有限，而且可能无法满足用户的所有需求。因此，许多用户希望能够在 ChromeOS 上安装第三方 APK。本文将介绍一种使用 ChromeOS 开发者模式和 shizuku 来优雅安装第三方 APK 的方法。这种方法可以让用户在不破坏 ChromeOS 安全性（即不开启开发者模式）的前提下，安装任何第三方 APK。本文的解决方案包括以下步骤：启用 Linux 开发环境与 ADB 调试安装 Shizuku 与第三方安装器使用 Termux 自动化授权启用 Linux 开发环境与 ADB 调试由于本机的有线ADB调试模式仅可使用本机相关虚拟容器调用，同时 Linux 开发环境选项中也有我们必要的 ADB 调试选项，因此必须开启 Linux 开发环境。Linux 开发环境的启用非常简单，具体可以参见我的上一篇文章：打造一台适合生产的Chromebook。[post cid="5" cover="https://pic.skihome.xyz/2023/09/14/6503069937bd3.webp"/]在 Chromebook 上，选择右下角的时间。依次选择“设置”图标 > 高级 > 开发者。在“Linux 开发环境”旁边，选择开启。按照屏幕上的说明操作。整个设置过程可能需要花费 10 分钟或更长的时间。系统会打开终端窗口。至此，Linux 开发环境已经正常安装在了 ChromeOS 上，终端程序将会自动打开，类似这样：安装 ADB 调试工具：sudo apt install adb安装后，输入adb即可使用 adb 工具。开启 ADB 调试：在系统的设置 > 开发者 > Linux 开发环境 > 开发 Android 应用 选项中，开启 "启用 ADB 调试"选项。[scode type="yellow"]注：此选项不可逆。若需要关闭 ADB 调试，则需要进行 Powerwash。[/scode]连接到 Android 环境：使用 adb devices命令，连接到 Android 环境。此时，系统会弹出提示框，询问是否允许此计算机进行调试，选择一律允许即可。现在，adb 列表中应该存在一个名为 'emulator-xxx' 的设备，并且状态为 'device'。安装 Shizuku 与第三方安装器Shizuku Github 项目地址：Github Release通过使用 Shizuku，可以让我们直接使用系统API。在 Shizuku 的 Github 项目地址中，下载最新的安装包。下载完成后，将其拷贝至 'Linux 文件' 目录下，这样我们可以使用 Linux 的 ADB 工具安装。在终端中，使用 install 命令直接安装该 apk 。应注意 apk 的目录是否正确，以及 adb 工具是否已经连接到本机 Android 环境。adb install shizuku.apk安装成功后，我们需要继续使用 ADB 工具对 Shizuku 进行授权：adb shell sh /storage/emulated/0/Android/data/moe.shizuku.privileged.api/start.sh授权后，打开 Shizuku，界面应该如下：可以看到，现在 Shizuku 已经被授予了权限，显示 "Shizuku 正在运行"的结果。现在，我们再通过 ADB 工具安装任意第三方安装器，并进行授权，即可完成通过 Android 自行安装任意第三方 APK。这里，我使用的是 InstallerX，也可以选择 R-安装组件等支持 Shizuku API 的第三方安装器。InstallerX Github 地址：Github Release类似上面的步骤安装即可。打开 InstallerX，并进行 Shizuku 授权。接着，打开"文件"应用，选中任意 APK，并点击上面的"打开"按钮，更改默认应用程序：至此，我们就可以通过 Android 环境直接安装第三方APK了。使用 Termux 自动化授权由于 Shizuku 依赖于 ADB 授权，但每次重启后 Shizuku 都需要重新授权，这就导致每次开机都不得不启用 Linux 环境并执行指令进行授权，这不符合我们的理想需求，因此我们可以使用 Android 环境下的 Termux 进行自行授权。安装 Termux：虽然 Termux 可以通过 Google Play 获取，但 Google Play 版的 Termux 已经停止更新，官方推荐在 Github 或 F-Droid 进行下载。Termux：F-DroidTermux: Boot：F-Droid将上述两个程序安装后，打开 Termux 。安装 ADB 工具：使用 apt 直接安装 android-tools。apt install android-tools安装后，可以使用 adb devices来让 Android 对于该 Termux 中的 ADB 工具进行授权。授权后，应和 Linux 环境一样显示 'emulator-xxx' 的设备，并且状态为 'device'。设置启动自动授权：在默认目录下，新建并进入目录：mkdir -p .termux/boot cd .termux/boot使用编辑工具，新建一个自启动脚本：vim auto-shizuku.sh脚本内容如下：adb devices adb devices adb shell sh /storage/emulated/0/Android/data/moe.shizuku.privileged.api/start.sh编辑好脚本内容并保存后，下次开机 Termux 将自动运行，并进行 Shizuku 授权。
写在开头在使用Tunnel模式连接VSCode的时候，我发现虽然Tunnel可以让不支持SSH的VSCode Web连接到个人服务器来获得几乎完善的使用体验，但是由于Tunnel会经过微软的服务器进行转发，这样一来一方面让编写代码的安全性有所下降，另一方面由于微软服务器在海外，连接的稳定性与延迟体验大打折扣。同时，在Chromebook上最明显的缺陷就是需要额外的一台机器运行VSCode，这使得Chromebook在无网络环境下编写代码的体验大打折扣。本文将介绍另一种部署方案，可以使Chromebook在无Linux环境下使用离线版VSCode。Code ServerRun VS Code on any machine anywhere and access it in the browser.Code-Server 是一款服务端程序，只需将它部署到服务端，即可在任何地方使用 VSCode。鉴于原生的 Chromebook 体验并不包括开启开发者模式以及 Linux 环境这两个选项，因此本文将从另一个子系统着手，即 Android 环境。本文的方案为：Termux + ConnectionForwarder + Code-Server。TermuxTermux 是本文的起点，也是运行 Code Server 的必要准备条件。Termux 是一款开源终端模拟器，可以免 root 运行Linux程序。没有启用开发者模式\ADB 调试的 Chromebook 无法安装第三方 APK，但 Termux 已经在 Google Play 上架(目前已停止更新)，可以通过 Play Store 下载安装。若可以安装第三方应用，请使用 F-Droid 下载最新版本的 Termux。打开 Termux 后，安装 tur-repo 与 code-serverpkg update pkg upgrade -y pkg install tur-repo pkg install code-server配置 Code ServerCode Server默认会从~/.config/code-server/读取配置文件。因此我们可以在该目录下新建配置文件。mkdir -p ~/.config/code-server/ vim ~/.config/code-server/config.yaml配置文件如下：bind-addr: 0.0.0.0:8080 auth: password password: PASSWORD cert: false其中bind-addr必须设置为0.0.0.0。配置好后，可以使用code-server命令来启动 code-server ，测试配置是否有误。此时我们无法通过浏览器访问 localhost 来进入 VSCode，因为 Android 环境在一个虚拟网络中，它与本机或局域网并不互通。打开 Termux 侧栏并新建一个 Session，在其中使用 ifconfig 指令，可以查看到 Android 环境的网络情况。其中，eth0 所对应的 ip 即为我们可以访问的虚拟ip。例如，此时我访问 100.115.92.2:8080 即可正常打开 Code-Server。但是，由于 Android 环境的ip并没有什么规律，若每次使用都需要访问该 ip，会略显麻烦。因此可以使用 ConnectionForwarder 进行 ChromeOS 上的端口转发。ConnectionForwarderOpen source Chromebook app for forwarding connections from/to different ports and interfaces (or to internal android IP)ConnectionForwarder 是一款端口转发的 Chrome 程序，其专为 ChromeOS 设计，用于转发本机的不同端口。该程序可以从 Chrome扩展商店 下载。安装该程序后，点击 CREATE RULE 按钮，将 Sources Address 设置为127.0.0.1(localhost) ，以免同一局域网下的其他用户访问；将 Destination Address 设置为 Android，同时将目标地址的端口设置为配置文件的端口，将源端口设置为任意端口，并点击 ADD RULE 保存配置。最后，确保打开了 Enable Forwarding与Enable Rule 两个选项。此时，我们就可以通过 localhost:port 访问 Code Server 了。欢迎关注我的公众号：Saki的避风港，获取更多有趣内容。
写在开头作为一名计算机专业的学生，和其他学生稍有不同的可能就是有些时候需要背着电脑去上课了。但是，每次都要背着那个3公斤重的游戏本上课下课，我们这些"体弱多病"的学生可能真的吃不消。因此，在去年末，我氪了一台洋垃圾，Chromebook Yoga C630。不到2000块钱，却有着i7的八代低压U，4K触摸屏，16G内存以及128G的固态emmc。在配置上，对于写文档、撸代码的需求应该算是足够了。但是，由于Chromebook预装的ChromeOS，本地化体验以及生产力方面都有些不足，本文将会介绍提升ChromeOS系统体验的一些方法，帮助你拥有一台在中国大陆体验更舒适的适合生产的Chromebook。开启开发者模式Chromebook的开发者模式可以帮助我们获取ChromeOS的root用户访问权限，可以对ChromeOS本身进行修改。其次，开发者模式会将软件包安装程序置入，这样就可以直接安装在Google Play以外的apk了。需要注意的是，开启开发者模式后，每次开机会出现一个长达30秒的警告画面。需要按下Ctrl+D跳过。注意，开启开发者模式会进行一次Powerwash，请提前备份好数据，以免数据丢失。具体开启步骤如下：将Chromebook关机。按下 Esc 键与 Refresh 键，按住后再按下开机键。在亮屏后，会提示警告信息，此时可以松开 Esc 与 Refresh 键，然后按下Ctrl+D组合键。下一步系统会提示你是否继续，按下Enter键继续。系统会进行 Powerwash，然后重新开机。此时Chromebook就开启了开发者模式。此时，ChromeOS会进入首次设置页面，在第一页找到"启用调试模式"按钮并单击。系统会提示设置root密码，需要设置一个稍微复杂的密码，以免被破解。根据流程激活Chromebook。使用MrChromebox缩短警告页面MrChromebox脚本可以帮助我们在受支持的Chromebook上安装完整的UEFI，使之可以安装Windows等其他操作系统，不过这部分不再本文讨论范围内。但是，这部分需要禁用固件写保护。在部分设备上，禁用固件写保护可能需要特定的线，甚至拆机扣下电池。若觉得过于麻烦，可以跳过此部分。缩短警告页面流程如下：激活Chromebook后，确保连接的网络可以正常访问全球互联网，然后，按下 Ctrl+Alt+T组合键，打开Crosh。输入shell并回车。现在，你的窗口应该是这样：随后，输入如下指令，执行MrChromebox脚本：cd; curl -LO mrchromebox.tech/firmware-util.sh && sudo bash firmware-util.sh脚本菜单应该和下面一样：输入选项3 Set Boot Options，然后根据需要设置短的警告时间即可。安装ChromebrewChromebrew是ChromeOS下的一款包管理程序，类似于macOS下的Homebrew。安装步骤如下：按下Ctrl+Alt+T组合键，打开Crosh。输入shell并回车，进入shell。输入如下一键命令，回车即可安装Chromebrew。curl -Ls git.io/vddgY | bashChromebrew提供的包可能远远没有其他Linux包管理器那么多，但是也算是满足了我们日常的使用。使用Aria2下载在Windows上，我们可以用IDM进行下载与管理，但在ChromeOS上没有相关软件，那么我们就只能用Chrome来进行下载了吗？当然不。Aria2支持 HTTP/HTTPS, FTP, SFTP, BitTorrent 和 Metalink 等多种协议，是一款功能强大、内存占用低的下载器。安装Aria2的步骤很简单，先使用Ctrl+Alt+T进入Crosh，然后输入shell进入shell。随后，使用crew 安装 aria2即可。crew install aria2随后，我们需要编辑一个aria2的配置文件，以便启用rpc。首先，我们新建一个aria2的配置目录，然后创建aria2.conf文件：mkdir -p ~/.config/aria2c vim ~/.config/aria2c/aria2.conf在文件中粘贴以下配置：# 设置加密的密钥 rpc-secret=123456 # RPC 开关 enable-rpc=true # RPC 跨域(WEB 界面需要跨域) rpc-allow-origin-all=true # RPC 外部访问(false 的话只监听本地端口) rpc-listen-all=true # RPC 端口, 仅当默认端口被占用时修改 rpc-listen-port=6800 # 单文件并行下载数 split=5 # 断点续传 continue=true # 同服务器最大连接数 max-connection-per-server=5 # 最小文件分片大小, 下载线程数上限取决于能分出多少片, 对于小文件重要 min-split-size=10M # 下载速度限制(0代表不限制)(示例值：500K、10M) max-overall-download-limit=0 # 单文件速度限制 max-download-limit=0 # 上传速度限制 max-overall-upload-limit=0 # 单文件速度限制 max-upload-limit=0 # 文件保存路径, 默认为当前启动位置 dir=/home/chronos/user/Downloads # 启用磁盘缓存这样，我们设置了一个rpc密码为123456，端口为6800，默认下载地址为"下载内容"目录的配置。接下来，我们使用如下命令来测试配置文件正常可用：aria2c --conf-path=~/.config/aria2c/aria2.conf至此，aria2的后端程序已经配置完毕，接下来需要使用一个Chrome插件拦截下载请求并发送至aria2后端。在这里，我推荐使用Aria2 Explorer。这是一款界面清爽的Aria2下载管理器，可以在Chrome 扩展商店下载：下载地址安装扩展后，右键扩展并点击"选项"，在"Aria2-RPC-Server"一栏填入rpc secret，并在后面设置下载路径，这里可以填写/home/chronos/user/Downloads，默认将下载到下载目录中。在"下载拦截"一栏中开启"自动拦截下载任务到Aria2"，在"监测Aria2状态"一栏中开启"监测Aria2下载状态"以及"任务状态通知"，这样即可在扩展图标中查看Aria2在线状态以及下载时会弹出通知。配置完成类似如下：随后，点击该扩展，将弹出Aria2 Explorer界面。点击"常规设置"——"RPC"，在RPC密钥处填写RPC secret。这样，Aria2的前后端配置就都完成了。安装Clash代理在国内，若想使用Google全家桶带来的便利，是一定需要代理的。目前主流的操作方法是在Chromebook上安装Clash for Android或其他代理软件，开启VPN。但这种方法需要打开一个Android程序并保持后台运行，这对于 x86架构的Chromebook来讲可能会更消耗内存与CPU。因此我们在这里使用原生Clash Core，在ChromeOS中启用Clash(不是Crostini)。首先，需要去Clash 的 Github Release 页面下载适配本机的 Clash 二进制文件。(本来我想直接用crew安装的，但竟然没有)Clash Github Release选择 clash-linux-[对应架构]-v1.gz 文件下载。下载后，在 "文件"程序中解压并将clash二进制文件复制到"下载内容"目录下。进入shell，输入如下指令：cd;sudo cp Downloads/clash /usr/local/bin/clash;sudo chmod a+x /usr/local/bin/clash;执行完成后，本机就拥有了clash。接下来，需要配置 clash。首先，config.yaml文件需要自备，保存在"下载内容"目录中。使用mkdir -p ~/.config/clash指令创建clash目录。然后，使用cp ~/Downloads/config.yaml ~/.config/clash/将配置文件保存至clash配置目录内。最后，输入clash启动clash。初次启动需要下载一些内容，可能较慢。启动成功后，即可配置本机代理。打开"设置"，在"网络"——"WiFi"内选择当前连接的wifi，进入配置。点击"代理"，输入clash代理，结果应该如下(端口需要输入config.yaml中的混合端口号)：至此，在clash开启的情况下，应不需要开启Android的任何VPN程序，即可访问国际网络。使用自启动脚本当然，若想贴近原生使用体验，每次开机打开shell然后打开clash或者aria2的操作属实不够优雅。那么，如何才能让clash或其他程序开机自启呢？在这里，我们需要用到"ChromeOS Autostart"扩展程序。该扩展程序可以在开机时执行一条指令，我们可以在这里设置执行需要自启动的程序。ChromeOS Autostart可以在 Github Release 里下载，可以下载zip版本的文件。下载并解压后，把扩展目录放置在合适的位置(因为添加到Chrome后不能删除)，然后添加到Chrome。在使用该扩展前，我们需要编写一个自启动脚本，这样就不用每次都修改该扩展保存的指令了。在shell中，首先执行指令cd，将目录切换到用户目录下(该目录不会因为系统升级而清理)。随后，输入 touch autostart.sh新建一个自启动脚本文件。使用 vim autostart.sh编写自启动脚本文件。注：此步若提示vim command not found是因为没有安装vim编辑器，输入该指令安装：crew install vim在autostart.sh中，自启动clash只需要输入如下内容即可：nohup clash -d /home/chronos/user/.config/clash/ </dev/null &>/dev/null &这样，clash即可在后台运行。最后，访问ChromeOS Autostart的配置页面，输入如下指令：sudo -S bash -x /home/chronos/user/auto_start.sh <<< "调试模式密码"在引号内输入设置的调试模式密码，然后按下Enter，即可保存开启启动指令。现在，可以重启试试效果了。由于上文我们使用了Aria2，但是经我测试发现同样的指令放在shell脚本中无法生效后台运行，因此在这里使用了一个折中的办法：使用screen后台运行。因此，上述指令需要在后面添加关于aria2启动的指令，完整指令如下：sudo -S bash -x /home/chronos/user/auto_start.sh <<< "调试模式密码";sudo screen -dmS aria2 bash -c 'aria2c --conf-path=/home/chronos/user/.config/aria2c/aria2.conf'常用指令的安装安装了Chromebrew后，我们就可以在ChromeOS内部安装一些常用的软件，例如vim、git等。安装步骤非常简单，就像上面安装aria2一样。例如，安装git:crew install git开启Linux只有Android以及PWA应用的Chromebook自然不配被称为生产力工具，因为在此情况下就连编译调试代码的能力都十分有限。因此，安装Linux容器是必需步骤。ChromeOS默认安装的Linux容器是Debian 11，如有需要可以切换至Archlinux。但由于与ChromeOS搭配效果并不尽人意，在这里不做讨论。Linux 默认处于关闭状态。您随时可从“设置”中开启它。在 Chromebook 上，选择右下角的时间。依次选择“设置”图标 高级 开发者。在“Linux 开发环境”旁边，选择开启。按照屏幕上的说明操作。整个设置过程可能需要花费 10 分钟或更长的时间。系统会打开终端窗口。现在，您已进入 Debian 11 (Bullseye) 环境。您可以运行 Linux 命令、使用 APT 软件包管理器安装更多工具以及自定义 shell。建议设置的容量大一点，方便安装一些IDE或者其他应用程序。更换国内镜像源若使用debian官方的源，会导致速度较慢。推荐更换置国内镜像源，访问、下载速度较快。一般情况下，将 /etc/apt/sources.list 文件中 Debian 默认的源地址 http://deb.debian.org/ 替换为镜像地址即可。Linux本地化之中文环境给Linux安排一个中文环境可以帮助我们更加优雅地使用Linux程序。首先，点开终端程序，执行以下指令进行中文字体的安装：sudo apt install fonts-noto-cjk fonts-wqy-microhei fonts-wqy-zenhei接下来需要配置默认locale，输入如下指令并选择zh_CN.UTF-8。sudo dpkg-reconfigure locales重启Linux后，即可看到程序默认使用中文显示。GTK下的中文显示在我们使用一些gtk的程序时，可能会感觉中文字体非常奇怪，看起来非常不舒服。此时我们需要调整gtk默认字体，使程序显示更加优雅。首先，我们需要gnome-tweaks这个程序，可以控制gtk的显示效果。安装gnome-tweaks：sudo apt install gnome-tweaks安装后，输入gnome-tweaks启动该程序。在"字体"选项中，设置"界面文本"与"文档文本"分别为"Noto Sans CJK SC Regular" 和 "Noto Sans Regular"。其他选项无需修改(修改后可能会导致莫名其妙的后果)。效果类似如下：自此，大多数GTK程序的中文显示都不会非常奇怪。设置完毕后，也可以将其卸载，以便留出更多空间。中文输入法ChromeOS自带的Linux环境是Debian 11，默认使用的是Wayland协议。在这里我们可以使用fcitx5来作为输入法引擎。使用如下指令安装fcitx5：sudo apt install fcitx5 fcitx5-chinese-addons fcitx5-frontend-gtk4 fcitx5-frontend-gtk3 fcitx5-frontend-gtk2 fcitx5-frontend-qt5然后编辑/etc/profile，将下述内容写入配置文件：export XMODIFIERS=@im=fcitx export GTK_IM_MODULE=fcitx export QT_IM_MODULE=fcitx接下来输入 fcitx5-configtool，进入fcitx5的配置页面。将 拼音 移到已左侧，激活拼音输入。点击中间的扳手图标，进入拼音的设置。开启云拼音。重启Linux后，可以使用 Ctrl+Space 来切换输入法(在Linux应用中)。Appimage Launcher使用在ChromeOS中，为了避免Linux容器软件包环境太复杂，可以尽量使用Appimage来进行软件的安装。Appimage的优点是将所有依赖库打包至一个软件包内，且不用安装，直接运行即可。Appimage Launcher是一款可以方便地管理Appimage的应用，它可以将Appimage同一保存至某一目录下，然后创建桌面图标(该图标可以被ChromeOS识别并显示在菜单中)。Appimage Launcher的安装非常简单，仅需在Github Release页面下载.deb格式的安装包并安装即可。下载地址在这个页面选择bionic格式的安装包，然后再"文件"应用中双击即可安装。SpaceFM 文件管理器ChromeOS自带的"文件"管理器属实鸡肋，大多功能都没有，并且在效率上也是捉襟见肘。因此，SpaceFM文件管理器出场了。发现 Linux SpaceFM 文件管理器的威力 - Linux.cnSpaceFM 是一款轻量、高效的文件管理器，比较适合在Chromebook这种性能不高的机器上使用。安装仅需一条指令：sudo apt install spacefm当然，此时SpaceFM管理器仅能管理Linux容器内的文件。因此，需要将一些目录映射到Linux中。打开"文件"应用，将"下载内容"目录映射到Linux中：右键"下载内容"目录，点击"与Linux共享"。然后，为了方便使用，我们需要创建一个软链接，将下载内容目录映射到Linux用户目录下：在Linux终端执行：ln -s /mnt/chromeos/MyFiles/Downloads ~/Downloads这样，即可在用户目录下直接操作"下载内容"目录。如需其他目录，同上操作即可。Stalonetray在使用ChromeOS自带的Linux时我们会发现，一些会有后台托盘图标的应用程序，关闭后明明在运行，但我们就是找不到托盘在哪。这种情况下，我们需要一个可以当作后台托盘的程序，帮我们显示后台在运行的程序。Stalonetray就是这么一款托盘程序。安装仅需一条指令：sudo apt install stalonetray默认配置下，输入stalonetray即可显示后台托盘，但是在一些高分屏设备下托盘就会显得非常小。在这个情况下，我们只需要在用户目录下新建一个配置文件，并编辑图标大小即可：cd; touch .stalonetrayrc vim .stalonetrayrc在配置文件中写入如下配置：background "#F2F2F2" decorations all geometry 4x1+0+0 icon_size 64这样，最终的显示效果就较为客观了。若觉得图标太大，可以按需调整icon_size的值。QQChromeOS虽然有原生Android的支持，若安装一个QQ HD或者移动版QQ，对于笔记本来说使用体验仍然非常割裂。因此，我们可以使用最新的linuxqq解决该问题。linuxqq仅需在官网下载最新版的deb安装包并安装即可。使用体验已经非常完美了。QQ官网微信 - Wine张小龙你不做人！！上文提到，ChromeOS的Linux容器默认使用Wayland协议，因此我试了几个不同的deepin-wine-wechat，皆出现一个大黑遮罩，盖住了微信本体。这个体验就像依托答辩。 这就根本没有使用体验。最后，我通过虚拟桌面的方式，勉强解决了该问题。效果如下：目前大部分功能完善，但是也有一些影响使用的问题：无法发送图片、文件无法打开公众号文章等内容音视频通话无法使用这也是无奈之举，如果linux下有完善功能的微信，也不会穷途末路去使用Wine来安装Windows 微信。张小龙你不做人！！！安装Wine，我们首先要启用32位库的支持。在linux终端中，输入如下指令。sudo dpkg --add-architecture i386然后，刷新软件包列表并安装wine。sudo apt install -y wine64安装好后，我们就可以在微信官网下载windows版的微信，然后使用wine进行安装了。但在此之前，我们需要配置wine的虚拟桌面。在终端输入winecfg并回车，进入wine的设置界面。单击"显示"选项卡，启用虚拟桌面。虚拟桌面的大小按需填写。可以填完保存重新执行winecfg进行测试。调整到合适大小后，使用wine安装微信。wine微信的文件注定无法非常顺畅地打开，但我们知道它保存的路径：~/Documents/'WeChat Files'/wxid_[id号]/FileStorage/File因此，我们可以创建一个软链接，让我们方便地访问微信的文件。ln -s ~/Documents/'WeChat Files'/wxid_[id号]/FileStorage/File ~/WXFileVisual Studio Code既然是计算机专业了，那么我们的VS Code肯定是必不可少的工具。VS Code的安装十分简单，仅需在官网下载.deb格式的安装包，双击安装即可。Visual Studio Code官网PyCharm/IDEAJetbrains家的两款IDE，分别对应Python与Java的程序开发。两款IDE的安装方式如出一辙，在这里仅介绍一款，另一款以相同的步骤安装即可。打开官网，下载所需IDE的.tar.gz包将安装包移动至Linux容器内解压.tar.gz包至自定义的Application目录内运行解压的IDE的bin目录内的xxxxx.sh文件(例pycharm.sh文件）IDE将会打开，然后点击左下角的齿轮图标，点击"创建桌面条目"，即可在启动其中创建图标。WPS Office对MS Office兼容性最好的Office套件，并且可以在Linux下使用的，也就属WPS一家了。OnedriverOnedriver是一款可以将自己的OneDrive挂载到本地目录的程序。推荐的Chrome扩展既然是叫ChromeOS了，不加点扩展还怎么好好地玩Chrome呢？这里推荐一些可以提升使用体验的扩展程序。Dark ReaderDark Reader可以将当前页面适配为夜间模式，在夜晚的时候不会让默认亮色的页面很刺眼，好用的地方是，它现在还可以根据系统设置的亮暗模式来进行自动调整，这样就让整个系统一体性更强了。Chrome 应用商店：Dark ReaderTampermonkeyTampermonkey是一款脚本加载器，可以加载各种脚本，来对页面进行一定程度的修改。Chrome 应用商店：Tampermonkey简悦简悦为当前页面提供了阅读模式，以及多种导出、保存当前文章的功能。Chrome 应用商店：简悦 - SimpreadFeedbroFeedbro是一款可以嗅探当前页面的RSS源的扩展程序。不仅如此，它还是一款RSS阅读器，可以订阅并管理RSS源。Chrome 应用商店：Feedbro附：将Feedbro Reader界面修改为中文的方法：右键这里复制汉化json文件链接点击扩展并点击 Open Feedbro Reader点击右上角的齿轮图标点击Settings中的 Import locate输入第一步复制的链接，并点击OK。这样就设置好中文显示了。Minimal Twitter它可以简化Twitter的一些不必要的栏目，让整个Twitter看起来更加清爽。Chrome 应用商店：Minimal Theme for TwitterWikiwandWikiwand可以让那个丑陋的维基百科变成现代化的页面样式。Chrome 应用商店：Wikiwand: Wikipedia ModernizedAwesome Screenshot这个扩展程序可以截图整个页面，也可以区域截图，在分享时比较方便。值得一用的PWA程序说起ChromeOS主打的应用程序，还是基于浏览器的PWA渐进式应用程序。这种程序说白了就是一个网页，不过它对于浏览器进行了一些适配，并且可以保存一些程序资源在本地，有些时候可以造成是一款独立APP的假象。若以下应用在浏览其中没有弹出安装按钮，直接在菜单里选择“创建快捷方式”即可，反正都一样。StackEditStackEdit是一款Markdown编辑器，它可以将md保存到多种不同的服务中。StackEdit官网：StackEditStackEdit中文版：StackEdit CNTwitter虽然Twitter争议比较大，但是作为PWA应用使用体验还是不错的。SpotifySpotify是一款线上的音乐平台。Spotify官网：SpotifyGifcapGIFCap是一款可以录制屏幕并将录制内容保存为gif的程序。gifcap官网：gifcapCapture QR CodeCapture QR Code可以使用摄像头扫描二维码并解析。官网地址：Capture QR CodeClipchampClipchamp是微软旗下的一款视频编辑软件。使用PWA视频编辑软件的优点是视频的渲染导出均在云端完成，并不消耗本机算力。Clipchamp官网：ClipchampOneDrive虽然前文介绍了Onedriver，但是在一些场景下，可能仍然需要响应更快的onedrive，因此在这里可以再备一个PWA版本的OneDrive。OneDrive官网：OneDriveFyDropFyDrop其实就是SnapDrop。这是一款无需安装即可在本地局域网传输文件的程序，仅需双端同时打开该页面即可。FyDrop：FyDropDraw.ioDraw.io是一款流程图绘制软件，它可以绘制多种图。官网：Draw.ioPhotopeaPhotopea是一款在线的图片编辑器，类似Photoshop，如果是轻量编辑图片，可以使用Photopea进行编辑操作。YesPlayMusicYesPlayMusic是一款高颜值的第三方网易云播放器。该播放器支持PWA/macOS/Linux/Windows。因此，ChromeOS用户可以使用Linux版AppImage，但是出于性能考虑，有基础的用户可以根据项目作者的提示将项目部署至服务器或Vercel。Github 项目：YesPlayMusic后记在使用了一段时间的Chromebook后，一些内容可能有了与之前不同的见解，这篇文章也因为很多原因一直没有发表。在之后的文章中，我也会分享更多更优雅地使用Chromebook的姿势，请大家敬请期待。
写在开头Crostini是Chrome OS的一个子项目，它以容器化、安全的方式将Linux shell和应用程序引入ChromeOS。这种使用容器化的方式来载入Linux环境，在一定程度保证了安全性问题，同时，相比于传统的VM来讲不会有许多效能问题。而在最新的Chrome OS中，默认安装的Linux版本为Debian 11(Bullseye)。该版本发布时间为2021年8月14日，已经是两年前的版本。最新的Debian 12 已经于2023年6月10日推出。本文将讲述如何在Chrome OS下安装以滚动更新为更新机制的Archlinux，从而取代默认的Debian 11。启用多容器支持在Chrome OS中，系统会默认安装Debian 11作为唯一的Linux环境，同时用户没有更改的方式，系统也没有提供多容器支持。但是，Chrome OS已经隐式地添加了该功能。只需启用flags即可。访问 chrome://flags 页面，定位到 #crostini-multi-container，并选择启用。选择启用后，需要重启一遍Chromebook进行激活。重新启动后，点击设置 > 高级 > 开发者 > Linux开发环境，此时应多出一个选项，即“管理额外容器”。在该设置项中，默认会有一个penguin容器，这就是Debian 11容器了。安装Archlinux创建容器在“管理额外容器”设置中，点击“创建” > 高级，这将打开一个个自定义容器镜像的界面。在该界面中，我们需要自定义一个容器名称，同时粘贴镜像服务器地址与映像别名。如果网络环境良好，可以使用官方镜像源：https://us.lxd.images.canonical.com/ archlinux/current如果网络环境较差，可以使用国内镜像源，但推荐使用官方地址。https://mirrors.tuna.tsinghua.edu.cn/lxc-images/ archlinux/current将容器名称、服务器地址以及映像别名填写好后，应该如下图所示：填写完成后，点击“创建”，此时应该会弹出一个终端窗口。稍作等候，应该就可以在终端看到新的容器”Archlinux“了。但别急，此时的Archlinux由于还没有安装与ChromeOS集成的访客工具，目前还处于无法使用终端打开的状态。我们是需要使用crosh打开。用户配置使用快捷键Ctrl+Alt+T，打开crosh。在crosh界面中，输入vsh termina，打开termina的管理工具。此时，我们可以输入lxc list来查看我们当前有多少容器。可以看到，我们刚才创建的新容器已经显示在了列表中。同时是Running状态。在这里，本文使用Archlinux2这个容器进行演示。接下来，使用lxc exec Archlinux2 -- bash来进入新创建的容器。注意，"Archlinux2"为你创建的容器名称，它会显示在Name列中。进入容器后，使用该指令查找默认的用户名：grep 1000:1000 /etc/passwd|cut -d':' -f1默认的用户名应为登录系统的邮箱地址。如果需要的话，我们可以对该用户名进行修改：pkill -9 -u old-username groupmod -n new-username old-username usermod -d /home/new-username -l newusername -m -c new-username old-username上述指令请将old-username替换为默认用户名，new-username替换为需要修改的新用户名。上述指令执行应为这样：随后我们需要为该用户设置一个密码。使用passwd username指令。注意username应替换为用户名，同时密码输入时终端没有提示。接下来，我们需要编辑sudo的配置文件，以便可以使用sudo：visudo在该文件中，找到%wheel ALL=(ALL) ALL一行，将前面的注释取消，同时为了能够在终端中使用，我们还需取消%wheel ALL=(ALL:ALL) NOPASSWD: ALL前面的注释。将用户添加至wheel用户组：usermod -aG wheel username此时，我们对于用户的配置就结束了，已经可以使用新用户来登录Arch了。输入exit退出Arch，但不要关crosh页面。安装访客软件包使用lxc console Archlinux2打开Archlinux，并使用新用户进行登录。首先需要做的是验证容器中的网络。若容器没有网络连接，则无法进行后续工作：ip -4 a show dev eth0若执行该指令后终端有输出，则代表容器有网络连接。编辑/etc/pacman.d/mirrorlist，将国内镜像源添加至文件顶部。# 清华源 Server = https://mirrors.tuna.tsinghua.edu.cn/archlinux/$repo/os/$arch保存后，执行sudo pacman -Syyu更新软件包缓存。为了能快速使用AUR，一种方法是直接安装Archlinuxcn源中的yay。我们需要在/etc/pacman.conf文件中添加ArchlinuxCN软源，在末尾粘贴如下内容即可。[archlinuxcn] Server = https://mirrors.tuna.tsinghua.edu.cn/archlinuxcn/$arch保存后，使用sudo pacman -S archlinuxcn-keyring导入 GPG key。添加完成后，使用sudo pacman -S yay安装AUR管理程序。使用sudo pacman -S base-devel安装打包工具，下面需要。使用yay -S cros-container-guest-tools-git安装cros访客工具。使用sudo pacman -S wayland xorg-xwayland安装wayland相关软件包，以使用GUI软件。全部安装后，需要执行下面的指令，用于启动相关GUI服务。systemctl --user enable --now sommelier@0 systemctl --user enable --now sommelier-x@0 systemctl --user enable --now sommelier@1 systemctl --user enable --now sommelier-x@1启用完成后，就可以退出容器了。输入exit退出登录，然后按下Ctrl+A，然后按Q退出容器。最后，右键终端应用，点击“关闭Linux”，停止所有Linux容器，然后再点击刚才创建的Archlinux容器，不出意外的话就可以在终端应用中使用了，同时在文件应用中，也可以访问容器内的文件。配置中文环境设置中文字体首先，我们需要安装一些中文的字体：sudo pacman -S noto-fonts noto-fonts-cjk noto-fonts-emoji ttf-sarasa-gothic安装字体后，由于默认locale并不是中文，因此各种软件仍不会使用中文进行显示。使用sudo vim /etc/locale.gen，去掉 en_US.UTF-8 UTF-8 以及 zh_CN.UTF-8 UTF-8 行前的注释。使用sudo locale-gen令生成 locale。使用echo 'LANG=zh_CN.UTF-8' > /etc/locale.conf设置中文为默认locale。至此，软件程序将默认以中文进行显示。但由于一些问题，若我们不进行配置，字体将默认使用日文字形进行显示。虽然可以正常阅读，但是看起来并不舒服。此时，我们需要编辑字体配置文件，以使用正常的中文字形。下载该配置文件：https://github.com/szclsya/dotfiles/blob/master/fontconfig/fonts.conf ，将该文件移动至~/.config/fontconfig，然后关闭Linux并重新打开，这样就完成了字体的配置。主题配置在默认的Debian 11发行版中，使用GUI软件会让人感觉Linux程序的UI和ChromeOS比较相洽，这是因为默认的容器带有GTK与Qt的主题。安装访客工具后的Archlinux容器也带有GTK主题，但却不带Qt主题。这里我们可以通过kvantum搭配Materia主题实现Qt程序不那么违和。Kvantum使用sudo pacman -S kvantum安装Qt主题管理工具kvantum。安装后，使用vim ~/.config/environment.d/qt.conf编辑配置文件。在文件内添加QT_STYLE_OVERRIDE=kvantum，使Kvantum生效。安装materia主题：sudo pacman -S kvantum-theme-materia编辑/usr/share/applications/kvantum.desktop，创建一个kvantum的快捷方式，该快捷方式会在ChromeOS的启动菜单中显示。sudo vim /usr/share/applications/kvantum.desktop内容类似如下：[Desktop Entry] Name=Kvantum Comment=Qt Theme Manager. GenericName=Tools Exec=/usr/bin/kvantummanager Icon=/usr/share/icons/kvantum.png Type=Application StartupNotify=false图标Icon可有可无，如需一个好看的图标，需要在网上搜索该图标，并保存至/usr/share/icons/kvantum.png。打开kvantum，点击“变更/删除主题”，在下拉列表中选择“MateriaLight”（也可以手动输入），并点击应用此主题。此时，所有Qt程序均可使用该主题进行显示。暗黑主题所幸的是，GTK与Qt都提供了黑色主题。Qt的黑色主题仅需在kvantum中将MateriaLight改为MateriaDark即可，GTK的黑色主题需要编辑/etc/gtk-3.0/settings.ini文件，将gtk-application-prefer-dark-theme改为1即可启用黑色模式。替换Debian如需将默认的容器替换为Arch，首先需要将所有容器关闭。打开crosh，使用vsh termina进入termina虚拟机。使用如下指令将默认容器替换为Arch：lxc stop --force Archlinux2 lxc stop --force penguin lxc rename penguin debian lxc rename arch penguin lxc start penguin
写在开头上回书说到，打造一台适合生产的Chromebook是多么地重要。这回我们再聊一聊基于浏览器的撸代码工具。对于性能孱弱的Chromebook来说，直接运行比较大型的IDE(PyCharm以上)会导致整个机器卡顿，编辑不流畅，甚至在IDE中写一些中文都需要安装linux下的中文输入法，双重减速机器运行。那么有没有一种方式，可以直接在浏览器中运行IDE来进行代码的编辑及调试呢？答案是肯定的。VSCode OnlineVSCode，全称Visual Studio Code，想必会写代码的各位对它都不会感到陌生。没错，除了全平台支持，它甚至还支持Web端。相较于本地运行的VS Code来说，VSCode Online的最大优势就在于不用在本地安装。Chromebook的可选存储从32G到256G，对于这种存储空间比较小的设备，VSCode Online独具优势。不过，Online的特性也成为了VSCode Online的一大致命缺点：无法离线使用。如果设备离线，那不得不使用本地的VSCode，因为Online版本甚至都无法打开。没错，VSCode Online就是这样的一款优点和缺点都十分突出的Web App。它无法将全部功能作为PWA离线运行，但是如果可以正常联网，它的表现和正常VSCode别无二致。贴近原生应用的体验在一天的使用后，我发现VSCode Online的使用体验于原生VSCode几乎一致。同样的代码高亮、代码缩略图、资源管理器等等，甚至顶端的菜单都得到了很好的还原。当然这不仅要靠微软的贡献，也需要Chrome的支持，方便PWA程序可以在窗口标题栏获得更好的扩展性。在底栏部分，设置于登录按钮还是在那个地方，状态栏功能完整，没有任何缺失。扩展部分可以说是VSCode Online在正常运行的情况下最大的缺点了。由于Online版的VSCode全部的功能可以说都是在VSCode服务器端实现，因此很多需要在本地计算的扩展都不支持Web版VSCode。只有一些声明支持的扩展才可以安装。例如，我想要测试运行代码的时候，就会想到Code Runner这个扩展。这个扩展可以自动帮我们执行一系列指令，用于在本地环境中编译运行代码。很显然，VSCode Online不支持运行测试，因此这类的扩展几乎都无法安装。并且，部分扩展只有有限的功能。例如Python扩展：在VSCode Online中，Python扩展仅可用作高亮显示的功能。VSCode Tunnel - 解决缺憾在上面的介绍中，我们知道了VSCode Online的诸多优点以及缺点。那么对于这些问题，有没有一种方式可以解决呢？答案也是肯定的。在VSCode 1.74版本，微软添加了一项功能：Tunnel模式。远程隧道允许您从任何地方的任何设备使用 VS Code 安全地访问您的计算机。也就是说，我们可以通过远程链接的方式链接到自己可以计算的搭载了VSCode的设备上进行运行测试，以及使用完整功能的VSCode。当然，这种方式也有一个不可忽略的前提：有一台可供使用的搭载了VSCode的设备。这个设备需要保持互联网链接，同时拥有足够的性能可供调试。若Github所提供的Codespace则可以无视这个前提，因为Github会提供可供调试的设备。但是必须要将代码上传至Github仓库。