Haotian Zheng

2021.9.17

 • 

51 学分的威力逐渐显现出来了,本周忙成狗,或者说好像看起来没怎么忙但实际上很耗费心力,主要就是在不停地 context switching 上,和 sponsor 一起的团队项目要不停开会,经常这边塞一小时那边塞一小时的,然后自己还在忙两人合作的硬件编程作业以及个人的事情(做面试 take home,采购吃的喝的,买换季衣服,做饭刷锅,视频聊天),因此总之在不停地地开关相应的软件,材料,网页以及联系窗口上,脑子里也要不停回想下一个项目之前做到哪里了。fully loaded 的后坐力大虽大,也不打算退课,好像也过了退课的时间了,最多后面把一门课改成 pass / fail。
面试的准备也不太好。至此想去的两个组一个是被备胎,一个恐怕也没下一轮了,继续准备其他的罢。
能察觉到自己的心态会有微妙的变化,和朋友商量想要去做的事情的时候不知道要怎么宣告这种变化,只能随口提一嘴看大家的反应。但即使是我想要去做的事情,不管是出于爱好的,还是出于私心的,眼见着也都没时间去做,只一直在要去做的准备部分那扇门不停地跨进来跨出去,因此 context switching 的成本更大了。

2021.9.14

 • 

IMG_20210912_124227
上一场面试结果出来了,意思是以后可以再聊 - 现在他们想要更强一些的人。反正秋招就是不停地投递然后面试,这个没过也没啥,继续面着,虽然这个组我其实还蛮喜欢的,要能 move forward 我就无脑签了。
从 Cee 那收了台 OSMO Action,没想好能干嘛,可能就拍拍然后试试能不能剪一个视频 - 不过后来发现这个东西可能更适合室内固定的地方用来做 devlog 或者 timelapse 之类的东西,出去的话一个是没有防抖,一个是广角镜头想要 telephoto 的效果只能后期数码 crop in,因此拍出来的素材比较棘手,可能目前我还没有思路怎么利用这些素材。至于又有变焦又有云台防抖的 OSMO Pocket,我另外一个朋友在打算买来着,准备回头看看他的使用心得。
听了好几集 Boiler Room 的 DJ Set,比如 Nic FanciulliKaytranada,和 Ash Lauryn。最近想学 Houdini 来着,但作业太多了,又要准备面试,不知道还有没有时间。

2021.9.9

 • 

面了一场 all-day interview,希望周末或者下周一能出结果。
开始看 Intro to Embedded System 这门课的作业了,发现自己很多不懂,像是缺了什么前置课程没上一样。只能硬着头皮翻各种文档。再加上 Practicum 也开始事情多起来了,感觉这学期会和上学期一样忙。
Diffuse 被我用 FinGameWorks 的开发者账号重新上架了,因为之前的付费记录在封号后无法获取,为了避免重新付费的问题,以及自己也不图什么收入只求软件还在商店上,这次上架的版本是免费全功能的,即 Diffuse 变成了一个免费无内购软件。此外,Interseasonal 和 Contrail 都是因为 FinGameWorks 所谓的“多次违规”而封号的,但 FinGameWorks 至今仍未被封号并且还能提交新软件,可见要么并没有什么“违规”,要么整个风控系统的逻辑十分自相矛盾。
听了 Soul - Only One (Joe Kay's Slowed Sade Edit)

2021.9.5

 • 

PXL_20210831_011014752-3
周一因为 Labor Day 继续放假,所以周日算是在一个三天假期的中间。
才发现黄金年代三人组(蛋堡 Soft Lipa,滿人 Manchuker,荊軻 Jnco)现在有了一个 YouTube 频道叫做有夠難約,于是连看了三集,分别是蛋堡自己,ØZI,9m88,十分有趣。
听了 EverybodyLittle by LittleMiss SummerMarigoldsTenderly峇里岛幻视你,看了 Free Guy 和 Netflix 关于 911 的纪录片。

2021.9.1

 • 

Screen-Shot-2021-09-02-at-00.17.49

开学第一周过半,事情没到忙不过来的程度但也不少,潜意识总觉得应该周五了才对,其实还只是周三的晚上,想起来丁丁历险记的那个 "what a week huh" 的 meme。
这周对我影响最大的就是,我的 Google Play 账号又被封了。要解释为什么被封很困难,因为似乎我的确有 violation 的地方,但整个封号流程又充满逻辑上自相矛盾的地方,更不用提 Google Play 一点也不透明的工单系统和充满疑问的永久封禁举措。


简单来说,我在今年之前一直使用的是 FinGameWorks 这个账户发布我的 Android 软件,这个账号在 15 年我刚注册的时候上架了一些很基本的软件,譬如 Stillness 这个小游戏和用 Processing 写的 METER clone。彼时 Google Play 的上架很简单,需要的 metadata 也极少,因此这几个软件毫无问题地上了架。18 年的时候 Google Play 开始要求更多的 metadata 信息譬如是否适合儿童使用,以及要求 privacy policy,而我当时正因为学校毕业和创业公司的问题处于 AFK 的状态,也就没再管 Google Play 的邮件,之后 Google Play 就因此把我的一些没有足够 metadata 的软件下架了,措辞也十分客气,读起来一点也都没有 violation 的感觉:

Hi developers at Justin Fincher,
Your app, Cyan, com.JustZht.Cyan, has been removed from Google Play because you have not made a child-directed declaration. Google Play developers are required to declare in the Play Console whether their app is primarily directed to children under the age of 13 as defined by the Children’s Online Privacy Protection Act (COPPA).
This app won’t be available to users until you submit a compliant update. If approved, your app will again be available with all installs, ratings, and reviews intact.
Action required: Declare whether your app is primarily child-directed
...
If you’ve reviewed the policy and feel this removal may have been in error, please reach out to our policy support team.
...
Thanks for helping us provide a transparent experience for Google Play users.

下架就下架呗,我的账号也并未因此受到任何限制,19 年至 20 年,我给我的一个软件推了大版本更新(Skyline),甚至在准备留学生申请期间连着发了五个新软件(UniLWP.Droid Tech Demo,Diffuse Free,Diffuse Paid,Metropolis,以及 Diorama),新增了大约 130k 的下载量,FinGameWorks 这个开发账户一直毫无问题。
接着在 20 年底,我的 UniLWP.Droid 框架成型,作为 Unity based LWP 计划的一部分,我注册了一个新的开发者账号准备专门分发相对简单,廉价,制作周期短的三维动态壁纸(相较于开发周期动辄 2-3 个月,全面采用 Material Components 原生界面的已有动态壁纸来说)来证明 UniLWP 的能力。这个新的账号,Interseasonal Software,在开始走第一个软件的上架流程后就突然被封了,原文如下:

尊敬的Interseasonal Software开发者:
您好!我们发送此电子邮件是为了通知您,您的 Google Play 开发者帐号已被终止。
终止原因:此帐号或相关帐号之前多次违反开发者计划政策和开发者分发协议(我们之前已向您在注册 Google Play 开发者帐号时所用的电子邮件地址发送电子邮件,其中做出了相关说明)。
根据我们违规处置流程的规定,如果您屡次或严重违反我们的政策,我们可能会终止您的 Google Play 开发者帐号及相关的 Google Play 开发者帐号。
您可以访问开发者政策中心,更详细地了解我们如何贯彻实施开发者计划政策。如果您已阅读相关政策,并认为此终止决定可能有误,请与我们的政策支持团队联系。
请勿尝试注册新的开发者帐号。我们目前不会恢复您的帐号。

我就很摸不着头脑,申诉后获得的回复也很套话:

After review of your appeal, we're unable to reinstate your developer account.
Your Google Play Developer account has been terminated due to multiple violations of the Developer Program Policies by an associated Google Play developer account. We’ve reviewed and confirmed this association.

行吧,此时我也准备动身去读书了,因此也就只当是 Google Play 算法的一个失误,没再去管。但考虑到学生身份的一系列问题,和我有关联的财务问题最好还是有一事少一事,还是需要一个新的开发者账号,托管在他人名下。于是我就注册了 Contrail Software 并将 FinGameWorks 的大部分软件转移至了这个账户下,并没再动过。这个账号也的确相安无事,在我读书的这半年维持着软件的上架状态。
接着就到了这学期开学前夕,看到 Diffuse 有 8 个月毫无更新的用户开始写信问我是不是放弃了这个项目,我也考虑给 Diffuse 修下 Android 12 上的一些问题,所以在结束苹果实习的那两周抽了点时间升级了下 LibGDX,Sentry,和 Material Componments 推了一个新的 beta 版本,然后就要开学了,索性我就把 beta 推到了 public release channel,开始了占总用户 10% 的渐进分发。
然后 Contrail Software 就被封了。这周二早上收到了一封和 Interseasonal Software 收到的措辞一样的信:

This is a notification that your Google Play Publisher account has been terminated.
REASON FOR TERMINATION: Prior violations of the Developer Program Policies and Developer Distribution Agreement by this or associated accounts as outlined in previous emails sent to the registered email address(es) of the Publisher account(s).
Google Play Publisher suspensions are associated with developers, and may span multiple account registrations and related Google services.
You can visit the Developer Policy Center to better understand how we enforce Developer Program Policies. If you’ve reviewed the policy and feel this termination may have been in error, please reach out to our policy support team.
Do not attempt to register a new developer account. We will not be restoring your account at this time.

都在说一个 “associated Google Play developer account” 的 “multiple violations”,但是不说哪一个账号的什么 violation,完全是让人猜的状态。我于是猜想是不是之前 FinGameWorks 那几个被 Google 下架的软件,于是去把那几个软件缺失的 metadata 全补上了,修改审核通过(也就是变为正常状态)后再选择了我自己下架,觉得这样应该就算是解决可能的 violation。值得注意的是,作为 Contrail Software 仅有的关联账户,FinGameWorks 此时直到今天仍然是活跃的,毫无被封号的迹象,这也是我不理解的一点,按理说如果按照邮件里说关联账号也就是 FinGameWorks 这么劣迹斑斑,不应该早就没了?但 Appeal 后结果还是一样:

After review of your appeal, we're unable to reinstate your developer account.
Your Google Play Developer account has been terminated due to multiple violations of the Developer Program Policies by an associated Google Play developer account. We’ve reviewed and confirmed this association.
Google Play Developer account terminations are associated with developers and may span multiple account registrations and related Google services. Do not attempt to register a new developer account. Any new accounts will be closed and your developer registration fee will not be refunded. We recommend that you use an alternative method for distributing your apps in the future.

仍然是毫无透明度的套话回复,和 Google Play Developer 的 Twitter DM 里也直说这个决定是 final,意味着似乎他们也不打算再多看一眼。


那么这意味着什么呢,首先包括 Skyline,Diffuse,Metropolis 在内的 Android 软件在 Google Play 上全部没了,也没有转移的选项,因为一旦封号,整个开发者后台就只有政策页面,而且一段时间内只能申诉一次,申诉被回复后就没有申诉按钮了。对用户来说比较麻烦,毕竟之前买的软件突然没了,像是跑路了一样。对我来说可能近期找工作也比较麻烦,Diffuse 算是我用 LibGDX 写 Kawase Blur 和 Domain Wrapping 的一个例子,原本还想用这个例子去面一些可能对图形学有要求的团队来着,结果现在用来示范的软件没了。此外简历上我还写着 Skyline 曾经是 Google Play 当日付费总排行第二名的软件来试图说明 Indie Business 上的成就,现在用来证明的软件也没了。

至于我准备怎么做,可能把这些软件改成完全免费甚至开源的版本,改包名后用 FinGameWorks 重新上架,至少保证我的独立开发 Portfolio 还在,找工作也好,保留作为独立开发者最后的骄傲也好,或者只是觉得“有人用我的软件我很开心” - 这倒不是被封之后突然开始求可怜起来,我在给很多用户的邮件里都是这么写的,如果不是这个心态,我也不会在 Reddit 上给用我盗版的人发正版的激活码了。至于 Google Play 的后续软件开发,比如 Diorama 或者几个还在 WIP 的项目,可能就完全不干了,因为我也不确定会不会因此又封我账号。

最后,至于我怎么想,我其实也没啥想法,我现在只是毫无波动地在这里记录整个过程,我也很累,觉得独立开发者这个爱好不太想做了。以前做独立开发者是觉得在创造而不是在消费,觉得自己能想用什么软件就自己做出来,这些都是好的 - 我也仍然相信这些,只是近期独立开发者的体验,很多时间并不是那么开心,受制于各种限制,或者是身份的原因,或者是实习条款的原因,我很长一段时间没办法更新或者发布软件,更多的时间是在和工单系统扯皮,获得类似于在政府机关能获得的套话回复,自己无能为力。当然也不是不可以再去发个 Medium 发个推,买个推广,给科技媒体发邮件求报道,采取一些媒体上的举措引起开发者关系的注意 - 去 Google 一搜,排名前几个的被封的账号都是这么要回来的 - 但我也没有这个时间和金钱去投入了,说到底,我也只是一个在 workload 据说很重的学校里里读研究生同时又在找毕业后的工作的普通学生罢了,与其继续在独立开发这个事情上挣扎浪费时间寻求账号解封,不如重新捡起来 hackathon 打打,又好玩又能 network,说不定还能拿点奖金。

最后,近期的很多事情,都更让我相信村上春树关于“站在鸡蛋一遍”的立场,这个怕是也不例外,不管 Google Play 造福了多少独立开发,里面的自动化系统一旦出了差错,接待我的工单人员也都像是傻子一样连个具体的原因都说不出来,对于他们来说只是上个班 another day another dollar,对我来说是这两年很多熬夜做出来的,我引以为豪的数字工艺品,突然就没了最官方的分发渠道,而没了官方渠道,基本上也就是没了。

2021.8.29

 • 

开学前的最后一周了。去 CMU SV 校区拿了新学期的材料,在 NASA 园区里,进门就有一个航天飞机的模型。参加了秋季学期的 orientation,还被 cue 到要发言讲个人经历。周六公园聚餐见了些同学,逐渐有了些线下上学的感觉。
除此以外没做什么事情,陪新来湾区的朋友采购些东西,顺便在华人超市买了些有的没的,榨菜,粽子,果啤,还有瓶旺仔牛奶。尝试给 UniLWP 修 bug 添加新功能,但发现之前写的代码已经快忘了什么意义,目前还没什么进展。和很久没联系上的笔友又联系上了,邮件里简短地聊了下现状。想要上 Computer Graphics 这门课但 petition 还没进展,return offer 暂时也没信息因此又开了 LinkedIn 会员准备投递秋招以及准备面试。
剩下的时间主要就在打游戏。花了十几个小时把 MGS V 在 PC 上又打了一半,因为之前在 XBOX 上通了一遍所以其实没啥新的,而且 PC 版还不像 XBOX 一样可以常驻后台一直修基地平台,因此进度也不算快,最后也厌倦了删了。
晚上睡不着爬起来又把宫崎骏的红猪看了一遍,提到红猪就又要推荐一遍讲宫崎骏和飞机的这个 YouTube 视频,特别是 Macro 进入飞行员的 limbo 看到飞机组成的白色飘带那部分。然后最近在听 COOL。很老的 Fusion,专辑封面很有趣,以前我爸放这个而我不知道名字的时候,就直接叫这张专辑"两根黄瓜"。

2021.8.24

 • 

周日的时候闲得没事,去 Product Hunt 上传了下 Hourglass 的信息,到周一晚上的时候差不多稳定在当日第八的程度,反响还行。只不过再看 PH,每日的 Product 不再是 App 为主,而更多的是服务,写作这篇博客之前去他们网页上一看就好几个:Newsletter Kit,Domain Finder,Startup Acquisition - 已然更加像是给创业者看的列表,而不再是独立开发者和应用爱好者们讨论好玩点子的地方。再加上穿插在列表中的推荐项目,各路人马私信寻求利益交换(即一赞换一赞),提交不到五分钟即有 SPAM 邮件询问是否需要机器人帮忙 vote - PH 已经不再那么好玩了,甚至我,即使一开始只是抱着玩玩的心态,在提交的时候也又在处心积虑地算计刷新列表的时间,然后在 Twitter 上转推他们 mention 我的推寻求曝光,即,我也成为了这种已经不太好玩的 maker 文化的一部分。
但这么要求一个网站回到过去也不是什么有意义的事情 - 别人要是要求我回到过去继续像本科一样翘课熬夜肝项目,我也只会耸耸肩说有什么好处吗,大家都在 move on 而已。最近还有一次比较明显地感受到了这种错位感,就是和已经毕业工作的一个校友朋友聊,提到学生时代的很多爱好,当然也包括上架独立 app,在他工作后也都无暇顾及,也并不觉得有意义再去做了。
再之前翻看独立开发者群,还有人提到感觉独立开发式微,看热潮变成了 3D / NFT / Metaverse,不知道 The Next Big Thing 是什么。我出于个人原因,当然是对 Metaverse 低看一眼,觉得是一种具有传销潜质,但包装的很科幻的思潮罢了,毕竟 meta 精妙的地方,就在于套娃一样的“不可证伪”和“装作自知”。但不管如何,这种对变化的切身感受我倒是没有什么要反驳的,如今世界一天一个样子,股价可以顷刻腰斩,国家可以一天沦陷,要说明天人类就开始打热核战然后十年内所有人被迫进 matrix 造 metaverse,好像也不是那么天方夜谭,甚至有种求仁得仁的喜剧之感。


最近听了啥:Everybody Wants To Rule The WorldSelf Care。最近看了啥:把 Daniel Craig 主演的几部已经上映的 007 全看完了。

2021.8.21

 • 

最近很多事情都是“在做了在做了”的状态。全职在找了,选课在看了,个人项目在上架了,驾照在办了。还有很多事情想做但连开头都没,比如比如把博客从 Ghost 迁移到 Nuxtjs 上,比如写个人游戏,比如找个时间去金门大桥看看海。在抉择做与不做乃至以此消磨时间的过程中,感觉一个人生活还是要有很强的自我调节能力,不然实在很容易一天就消磨过去了。



Hourglass 上架了,可以从 Mac App Store 下载。我还在想要不要顺手把 Diffuse Mac 给做了,但好像也没太多时间。

2021.8.15

 • 

实习结束了,有成就也有缺憾,不过暂时也不太去考虑这些,距离开学还有两周,想先放松下,然后把之前拖延的事情都给做下。
想起来临走之前和大组老板告别,他说等后面可以线下一起喝个酒之类的,说完好像想起来了什么又确认说你达到能喝酒的年龄了对吧,还挺出乎我意料的。都知道我在读研究生了,想来再怎么也不至于这么年轻,更何况来加州后一直懒得去剪头,现在是头发长到像是狮子,日常要靠帽子来压住头发的状态,整个人可能看起来更为年老落魄些 - 至少我妈和我视频电话的时候是这么说的。
然后就是,和朋友聊天的时候还提到,看到还在读本科的实习生对于在苹果实习十分兴奋,这我当然是能理解的,我也一样。只是他们谈及苹果的时候,多了一种发自内心的自豪感,处处以“我们公司”来称呼,让我想起来之前我本科的时候拿个百度的月饼就好开心要发朋友圈,有种崇拜公司,靠称呼来获取更大的组织的认同感的感觉。这也是能理解的,不管是发自内心的开心也好还是有意识地借力公司的存在感,我都没意见,只是觉得大可不必积极把自己融入到公司的 narrative 里。当然,也可能是我过于警惕大型公司这种组织性的设置,也过于注意个人空间了,但于我而言还是这样舒服些,更何况最近公司的一些新闻并不光彩,甚至到了一种反讽的程度 - John Gruber 曾经在博客里对 Facebook 工作的人表达近乎迫害的意图,即 - 你选择在这家公司呆了下去,那你活该简历烂没人要 - 这种观点还有人小丑一般地附和以及辩解,而当苹果一样做了似乎是恶的事情的时候,不知道 John 会不会因此一样一杆子打死所有苹果员工。我这里甚至不是在讨论最近公司的政策是否对与错,而是盲目把人和公司绑定在一起是一种多么危险,甚至在 John 这个语境下可以称之为伪善的举动。

EDIT:想起来似乎是这半年来第一次如此旗帜鲜明地发表看法,但无所谓了,这个博客已经叫 echo chamber 了。what do you expect?

Taking screenshots of SwiftUI views on macOS (Swift 5)

 • 
import SwiftUI

extension View {
    func imageRepresentation(rect: CGRect) -> NSBitmapImageRep? {
        let hosting = NSHostingView(rootView: self.frame(width: rect.width, height: rect.height))
        hosting.setFrameSize(rect.size)
        hosting.setBoundsSize(rect.size)
        hosting.layout()
        hosting.layerContentsRedrawPolicy = .onSetNeedsDisplay
        hosting.setNeedsDisplay(rect)
        if let imageRepresentation = hosting.bitmapImageRepForCachingDisplay(in: rect) {
            hosting.cacheDisplay(in: rect, to: imageRepresentation)
            return imageRepresentation
        }
        return nil
    }
    
    func asImage(rect: CGRect) -> NSImage? {
        if let cgImage = imageRepresentation(rect: rect)?.cgImage {
            return NSImage(cgImage: cgImage, size: rect.size)
        }
        return nil
    }
    
    func asJpegData(rect: CGRect) -> Data? {
        return imageRepresentation(rect: rect)?.representation(using: .jpeg, properties: [:])
    }
}

Usage:

let view = AnyView(<Your View Here>)
let imageData = view.asJpegData(rect: CGRect.init(x: 0, y: 0, width: 128, height: 128))