Blog logoJustZht

Blog logo

2018.11.2

 • 

说说最近做了些啥

Skyline

Skyline 目前仍然在 alpha 封闭内测中,没有推到 beta 的原因是 1) 关键的地图黑屏 bug 还没有完全解决 2) 在一些 Android 定制系统(比如 MIUI)中会出现 UI 和稳定性上的问题,我估计需要去弄台对应的手机才能确切知道到底发生了什么,明天会去趟小米之家。
把手头一个 max 格式的上海的城市模型折腾了下变成标准材质,然后导出到 twinmotion 里面,效果还不错。twinmotion 是一个类似于 lumion 的建筑可视化渲染软件,目前看来视觉效果比 lumion 好的多,软件界面和逻辑也更好一些。如果 twinmotion 在这几天的实验里面效果不错,Skyline 2.0 的预告片估计会来得及完成。
上海模型渲染图:
2018-11-02-01.24.51
2018-11-02-01.24.56

Starry

Starry 是自己在实验 Unity 动态壁纸过程中的另外一个作品。Skyline 是 Android 动态壁纸,而 Starry 是 Windows 动态壁纸。这个项目基本上就是两天拿 WinForms 和 Unity 魔改的结果,但效果还不错,因此上架了 Microsoft Store,兑换码在这里
Starry 虽然上架了 Microsoft Store,但严格来说并不是一个 UWP 软件,而是一个 win32 软件,其 UWP 的外壳通过 Advanced Installer 转制得到的。后期 Starry 也许会加入更多的相机视角(这块是用 Cinemachine 做的转场)和一些基本的后期处理效果,也许不会,毕竟 Starry 只是一个试验性的东西,旨在证明 Unity 在主流平台魔改的可能性。
顺带一提,Starry 移植到 macOS 也并未难事,等这些事情都做完后我会写一篇文章专门说怎么调用两个桌面操作系统的 API 对 Unity 窗口进行调整,然后也许会在 Asset Store 发布一个针对 macOS 的动态壁纸 Toolkit。

一些其他项目的计划

准备更新下 portfolio,换用 Wordpress + Docker。
因为被 Ghost 2.0 恶心到了,只能本地写好再上传。在寻求 Mac 上的 Markdown 客户端过程中发现还是没有最满意的,于是又动了重写 Cetacea 的念头。
Epoch 做了惯常的依赖更新,整个系统仍然停留在 “模拟器” 的阶段。我也想多做一点,但是整个项目的规模太大,一天花上半小时根本没办法系统地做上什么。之前和别人聊天还谈到这个事情:
“你财富自由了准备干嘛呀”。
“我估计就去写 Epoch 了,有钱有时间,不用担心饿死”
“那你为啥不直接雇上几十个人帮你写”
“不不不,这个项目就是要靠自己写把整个宇宙都模拟下来,才有那种感觉”
虽然听起来很可笑但是的确就是这个样子,我也只能寄希望于我啥时候能天降横财让我财富自由去写 Epoch 了。

玩游戏

买了 Party Hard 2,相比第一代这个游戏真的是太难了,特别是标注眼睛的保镖,基本上见到就会游戏结束,导致真正的乐趣反而很容易就没了。
上个月还玩了休闲向的皮皮,记得在去合肥看猫猫的火车上都在打这个游戏。要分析的话,这个游戏做的成功的地方在于每局时间不会占用很长时间,到后期不花钱推关卡又很容易耗尽体力值,但是偶尔运气好了总能过关,这条让玩家惦记的线拿捏的很准。
貌似还玩了 Thumper 手机版,我倒是很好奇他的抗锯齿怎么做的。

喝水

在北京呆了一段时间,天气太干燥了,每天起床像是噎了钉子一样,说话特别疼。只能不停喝水,寄希望于补水会让喉咙好些。最近还吃了好几次满记甜品的白雪黑糯米。

听音乐

听了 Sun FlowerTime Moves Slow(这首之前在 Soulection 还是 Voyage Funktastique 里面作为 Mix 的第一首过),Come InsideVoyageBehaveSlinky Man

2018.10.30

 • 

这篇文章是在 Sublime Text 里面敲出来的。原因是我把 Ghost 从 0.11 升级到了 2.x 后发现 Ghost 2.0 内置的文本编辑器对中文拼音输入特别差,有点类似于 iOS 开发里面在 UITextField 没有做好对 Multistage Text Input 的支持的感觉(拼音输入有 Marked 和 Commited 两种 Stage),在拼音尚未完全输入的时候就自动格式化为纯文本了。至于升级 Ghost 的原因是愿愿说我的 RSS 挂了,我感觉像是之前的 Ghost 没有做好 escaping 于是决定升级大版本,结果还不能一次性升级到 2.0:
2018-10-30-11.19.43
总算是折腾好迁移之后进入后台发现那篇导致 RSS 挂掉的文章文字之间里面多了很多红点,不知道是 BOM 字符还是什么奇怪的东西,删除了之后终于能够输出格式正确的 RSS 了。
为了升级 Ghost 2.0 给当前在用的主题(魔改版 Daring)做了一些适配,顺便把主题色和 Banner 换了。
这次适配完我就不想再继续用 Ghost 了,把 MD 编辑器变为支持 MD Block 的富文本编辑器这个事情之前就让我一直没有升级到 1.x,结果 2.0 还是有这么多恶心的事(比如说富文本编辑器的 MD Block 插入图片不能像之前一样写好 ![]() 然后点击上传了,因为两栏预览功能貌似取消了,其次只能点击 Block 下方的插入图片按钮选择图片)

2018.10.14

 • 


偶尔翻了下 timehop 才发现刚好一年前的今天是校招季,对比下最近这两个时间还挺接近。
当时我恐怕不知道后面一整年的自己会那样疲于奔波,真是漫长的一年啊。

LogMeow

 • 

写 Skyline 的过程中发现 Android Studio 的 Logcat 界面经常假死,于是自己尝试写了一个 Logcat 界面,基于 kotlin-graphics/imguicosysoft/device。dear IMGUI 比 Unity 的 IMGUI 强大许多,写起来也比较有趣。

导出后就是一个 jar,可以运行在 macOS / Windows 上。

2018.8.3

 • 

Skyline 2.0 写了一半多了,因为重写的缘故遇到了一些之前没遇到的问题,估计发包还要推后一些。
写 Skyline 需要很多 Android 测试机,因此从家里搜了五六台设备用于测试,其中有一台 15 年买的坚果 Y601。这台 Y601 从买回来之后就一直只要卡顿就自动重启,之前折腾了半天总算是升级到了 Smartisan OS 3.x 版本,这次发现系统提示可以升级到 4.2 进入升级界面却显示无网络,因此点了重置手机想看看清楚数据后会不会好些,哪知道重置后卡在了激活界面提示无法连接网络。在论坛里搜了半天后才知道 3.8 以下版本网络激活的通道关闭了,只能手机卡激活。而我也没有大卡可以塞进去激活,因此直接下了一个 OTA 包 sideload 进去了。
这个事情让我哭笑不得,一个做手机的厂,自家深度定制的 OS 在版本兼容上出了各种问题,之前 2.x 版本升级签名不对,需要手动安装新的系统更新 apk 才能检测新的 OTA,然后是应用商店里的微信签名不对导致更新后数据丢了,还有这次老系统的激活验证通道直接关闭,实在不像是一个正常厂商干的事情,毕竟我这种独立开发者玩票随时弃坑就算了,商业公司关闭接口竟然也没有 API fallback 或者远程弹窗提示,让普通用户干瞪眼送修吗,况且 Google 地图应用现在仍然可以在十年前的 Android 0.9 系统上查看,iOS 6 的 App Store 仍然能获取商店信息和下载更新,这些公司对老系统的接口兼容性可算是比锤子这种一个版本号就过不去的做法不知成熟到哪里去。
这个事情让我坚定了自己的软件最好不要带服务端的想法,毕竟之前就写过这个事情,优雅但因为服务关停而无法使用的软件太多了,还是数据自给自足的软件更有生命力些。
这个事情也让我对自己发展的选择隐隐的担忧更加深了些。身边的人都去大厂锻炼,不出意外我也是要去腾讯的人(目前因为延期毕业和一个其他事情暂时推到八月中下了),去大厂相比创业公司主要就是看工程,看这类流程和大项目才会有的问题,而如果我又去折腾一些不成熟或者求快的东西,我会真的有收获吗,我还是没想通。

2018.7.29

 • 

FKJ Beijing Live

去北京看了场 FKJ 的演出,应该是北京首演了。

FKJ 是这两年来最喜欢的音乐家,说来有趣,我的 Skyline 动态壁纸 就是听着他的 Skyline 写出来的,软件名字也因此或多或少地顺手叫了 Skyline。
之前这个票价让我觉得有点太便宜了(或许是早鸟票的原因),毕竟是大佬来华。初到现场时以为不会有太多人,哪知道排了两层楼的队伍,组织有些不利等到了十点才正式开始。至于 Live 怕是不可言说只能亲身感受,最后返场的时间也超长,把 Vibin Out 和 So Much to Me 都演了,十分满足。
顺带一提,暖场的 HFigures 也不错,还专门搜了下,Deep Diving 挺好听,喵喵也喜欢这类 Jazz hiphop。

Skyline LWP

2.0 正在编写。的确还是跳票了,由于学校的考试,课设,延期毕业,个人的办签证,去北京处理东西等其他事项,2.0 从三月份拖到现在,让我自己都有一种赚了钱就跑的感觉,但是这么就太不厚道了,而且 1.0 版本问题的确很多,于是最近有些空,完全重写了下。
这次仍然没有摆脱 Unity,原因是 Android 上暂时没找到一个现代的的对开发友好的 Scene Graph / 游戏引擎:

  • ViroCore API 设计非常适合有 SceneKit 经验的人,但是暂时不支持自定义着色器,因此没办法做到根据高度图实时 Vertex Offest,而如果手动构造 Mesh 的话为啥不用 Unity 有现成的 Mapbox SDK 呢?
  • Rajawali 太老了,以及文档不够
  • libGDX 是一个跨平台的引擎,然后生成的 Gradle 项目是 Native 和游戏主干分开的,我试了一会还是觉得太憋屈了
  • UrhoSharp 配合 Xamarian 差点就成功了。Urho3D 本身功能强大,但是死在了不知道怎么用 C# 绑定去把 UrhoSharp 的视图扔到 Wallpaper.Engine 里面去
  • Sceneform,谷歌亲生框架,但是目前只能在 ARCore 里面用
  • Ogre,emmm 我忘了,反正应该也是觉得用起来难受

因此,在没一个能打的情况下,Skyline 2.0 还是用了 Unity,不过这次带了 LWRP ,期许能对移动设备更友好一些。

至此,图形前端还是 Unity,但 UI 部分完全是 Android 原生了,再也不会有因为 Unity UGUI 导致的奇怪的横屏布局问题。
之前 Unity 和 Android 对于每个功能都是单独写接口做传递,维护到后面就会有很多问题,比如状态的同步,回调的处理,异步调用因为 Unity 在后台 inactive 导致的阻塞等。因此这次使用了一个全局的 JSON 同步状态。为了避免之前为了每个属性在两边都 getter / setter 写面条代码的问题,这次在 Unity 端写了一个通过 Attribute 定义属性到 JSON 路径的映射功能,运行时在解析 JSON 后直接用反射查找属性 setter 调用,方便了很多,不过也因此选不了 il2cpp 作为 scripting backend,只能使用 mono。但其实也没什么,毕竟 il2cpp 对于我来说较为突出的优点在于 arm64 支持,但 Mapbox 的 Unity SDK 内嵌了一个 SQLite Wrapper 目前是只有 x86 和 armv7 库的,因此 arm64 显得聊胜于无。总之,stay tuned,以及希望我这次不要像之前为了一个宣传片直接跳票两个月

Unity 后期处理保证背景颜色

 • 

Unity 后期处理中如果用了 Color Grading 之类的效果器同时要保证相机背景颜色不变(比如 Unity 作为一个 View 挂在手机客户端中),就要费些功夫,因为使用多相机(一个背景相机+一个实物渲染相机)仍然是无法保证相机背景不被 depth 较高的相机上的效果器处理的,因此写了个根据相机渲染深度信息来填充特定颜色,挂在 Color Grading 后面即可。

namespace FinGameWorks.Scripts.PostProcess
{
    using System;
    using UnityEngine;

    [RequireComponent(typeof(Camera))]
    [ExecuteInEditMode]
    public class MaskedFirstPass : MonoBehaviour
    {
        [Range(0f, 3f)] public float depthLevel = 0.5f;
        public Color backgroundColor = Color.white;

        public Shader _shader;

        private Shader shader
        {
            get { return _shader != null ? _shader : (_shader = Shader.Find("MaskedFirstPassShader")); }
        }

        private Material _material;

        private Material material
        {
            get
            {
                if (_material == null)
                {
                    _material = new Material(shader);
                    _material.hideFlags = HideFlags.HideAndDontSave;
                }

                return _material;
            }
        }

        private void Start()
        {
            if (!SystemInfo.supportsImageEffects)
            {
                print("System doesn't support image effects");
                enabled = false;
                return;
            }

            if (shader == null || !shader.isSupported)
            {
                enabled = false;
                print("Shader " + shader.name + " is not supported");
                return;
            }

            GetComponent<Camera>().depthTextureMode = DepthTextureMode.Depth;
        }

        private void OnDisable()
        {
            if (_material != null)
                DestroyImmediate(_material);
        }

        private void OnRenderImage(RenderTexture src, RenderTexture dest)
        {
            if (shader != null)
            {
                material.SetFloat("_DepthLevel", depthLevel);
                material.SetColor("_BGColor",backgroundColor);
                Graphics.Blit(src, dest, material);
            }
            else
            {
                Graphics.Blit(src, dest);
            }
        }
    }
}
Shader "MaskedFirstPassShader"
{
   Properties
     {
         _BGColor ("Background Color", COLOR) = (1.0,1.0,1.0,1.0)
         _DepthLevel ("Depth Level", Range(1, 3)) = 1
         _MainTex ("Source", 2D) = "white" {}
     }
     SubShader
     {
         Pass
         {
             CGPROGRAM
 
             #pragma vertex vert
             #pragma fragment frag
             #include "UnityCG.cginc"
             
             uniform sampler2D _CameraDepthTexture;
             uniform half4 _MainTex_TexelSize;
             uniform float4 _BGColor;
             uniform fixed _DepthLevel;
 
             struct input
             {
                 float4 pos : POSITION;
                 half2 uv : TEXCOORD0;
             };
 
             struct output
             {
                 float4 pos : SV_POSITION;
                 half2 uv : TEXCOORD0;
             };
 
               output vert(input i)
             {
                 output o;
                 o.pos = UnityObjectToClipPos(i.pos);
                 o.uv = MultiplyUV(UNITY_MATRIX_TEXTURE0, i.uv);
                 #if UNITY_UV_STARTS_AT_TOP
                 if (_MainTex_TexelSize.y < 0)
                         o.uv.y = 1 - o.uv.y;
                 #endif
 
                 return o;
             }
             
              sampler2D _MainTex;
                float4 _MainTex_ST;
         
             fixed4 frag(output o) : COLOR
             {
                 float depth = UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture, o.uv));
                 depth = pow(Linear01Depth(depth), _DepthLevel);
                 if (depth < 0.5)
                 {
                                float4 color = tex2D(_MainTex, 
                       UnityStereoScreenSpaceUVAdjust(
                       o.uv, _MainTex_ST));	
                       return color;
                 }
                  else
                 {
                    return     _BGColor;
                 }
             }
             ENDCG
         }
     } 
}

Unity 项目打包 Framework 方式嵌入 UnityGetGLView 到 iOS 工程 (1)

 • 

距离上次写这个话题快有一年了,上次也是做外包的时候有嵌入 Unity View 到 iOS 工程的需求。这次为了双方的便捷,参考 unity-ios-framework 采用了打包整个 Unity 为静态 framework 的方法,这种方法对甲方非常友好,一次配置,以后每次只需更新 framework 和 Data 即可,而自己需要多做些配置,为了把这块也自动化,写了个 Build Script。

#!/usr/bin/env bash
if [[ -s "$HOME/.rvm/scripts/rvm" ]] ; then
source "$HOME/.rvm/scripts/rvm"
elif [[ -s "/usr/local/rvm/scripts/rvm" ]] ; then
source "/usr/local/rvm/scripts/rvm"
else
printf "ERROR: An RVM installation was not found.\n"
exit 128
fi

# rvm default
# ruby -v
# rvm use system
# ruby -v

echo $SHELL
which ruby
set -e

export LANG=en_US.UTF-8
export LANGUAGE=en_US.UTF-8
export LC_ALL=en_US.UTF-8

if ! which ruby > /dev/null; then
echo "error: ruby is not installed."
exit 1
fi

if ! which xcodeproj > /dev/null; then
echo "error: xcodeproj 没有安装,请 [sudo] gem install xcodeproj [--user-install],如果通过 rvm 使用了其他版本 ruby 请先 rvm use system 再 install"
exit 1
fi

chmod u+x $SRCROOT/UnityOutFramework/UnityPreBuild.rb
cd $SRCROOT/UnityOutFramework
ruby UnityPreBuild.rb

在 $SRCROOT 下面新建文件夹 UnityOutFramework,放置 Info.plist 和 UnityPreBuild.rb,内容如下

require 'xcodeproj'
include Xcodeproj::Project::Object

puts "检查 Unity 项目所需设定"
project_path = '../Unity-iPhone.xcodeproj'
project = Xcodeproj::Project.open(project_path)

deleted_targets, preserved_targets = project.targets.partition{ |target| target.name == 'UnityOutFramework'}

puts 'Deleted : '
puts deleted_targets
puts 'Preserved : '
puts preserved_targets

project.targets.replace(preserved_targets)

puts 'Added : '
target = project.new_target(:framework,'UnityOutFramework',:ios)
puts target

puts '-------- Config Names --------'
target.build_configurations.each { |config|
    puts config.name

    config.build_settings['HEADER_SEARCH_PATHS'] = '$(inherited) $(SRCROOT)/Classes $(SRCROOT) $(SRCROOT)/Classes/Native $(SRCROOT)/Libraries/bdwgc/include $(SRCROOT)/Libraries/libil2cpp/include'
    config.build_settings['LIBRARY_SEARCH_PATHS'] = '$(inherited) $(SRCROOT) $(SRCROOT)/Libraries'
    config.build_settings['GCC_PRECOMPILE_PREFIX_HEADER'] = 'YES'
    config.build_settings['GCC_PREFIX_HEADER'] = 'Classes/Prefix.pch'
    config.build_settings['ALWAYS_SEARCH_USER_PATHS'] = 'NO'
    config.build_settings['ARCHS'] = '$(ARCHS_STANDARD)'
    config.build_settings['INFOPLIST_FILE'] = 'UnityOutFramework/Info.plist' 
    config.build_settings['CODE_SIGN_STYLE'] = 'Automatic'
    config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = 'com.JustZht.UnityOutFramework'
    config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '8.0'
    config.build_settings['ENABLE_BITCODE'] = 'YES'
    config.build_settings['MACH_O_TYPE'] = 'staticlib'
    config.build_settings['DEFINES_MODULE'] = 'YES'
    config.build_settings['GCC_C_LANGUAGE_STANDARD'] = 'gnu11'
    config.build_settings['GCC_ENABLE_CPP_EXCEPTIONS'] = 'YES'
    config.build_settings['CLANG_CXX_LANGUAGE_STANDARD'] = 'gnu++14'
    config.build_settings['CLANG_CXX_LIBRARY'] = 'libc++'
    config.build_settings['GCC_ENABLE_CPP_EXCEPTIONS'] = 'YES'
    config.build_settings['CLANG_ENABLE_MODULES'] = 'YES'
    config.build_settings['CLANG_ENABLE_OBJC_ARC'] = 'YES'
    config.build_settings['CLANG_ENABLE_OBJC_WEAK'] = 'YES'
    config.build_settings['CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING'] = 'YES'
    config.build_settings['CLANG_WARN__DUPLICATE_METHOD_MATCH'] = 'YES'
    config.build_settings['GCC_WARN_ABOUT_RETURN_TYPE'] = 'YES'
    config.build_settings['GCC_THUMB_SUPPORT'] = 'NO'
    config.build_settings['GCC_USE_INDIRECT_FUNCTION_CALLS'] = 'NO'
    config.build_settings['MTL_ENABLE_DEBUG_INFO'] = 'NO'
    config.build_settings['UNITY_SCRIPTING_BACKEND'] = 'il2cpp'

    if  (config.build_settings['OTHER_CFLAGS'] == nil)
        config.build_settings['OTHER_CFLAGS'] = '$(inherited)'
    end

    if !config.build_settings['OTHER_CFLAGS'].include? "$(inherited)"
        config.build_settings['OTHER_CFLAGS'] << ' $(inherited) '
    end
    
    if !config.build_settings['OTHER_CFLAGS'].include? "-DRUNTIME_IL2CPP=1"
        config.build_settings['OTHER_CFLAGS'] << ' -DRUNTIME_IL2CPP=1'
    end

    # LINKER FLAGS
    if  (config.build_settings['OTHER_LDFLAGS'] == nil)
        config.build_settings['OTHER_LDFLAGS'] = '$(inherited)'
    end

    if !config.build_settings['OTHER_LDFLAGS'].include? "$(inherited)"
        config.build_settings['OTHER_LDFLAGS'] << ' $(inherited) '
    end
    
    
    if  !config.build_settings['OTHER_LDFLAGS'].include? "CoreMotion"
        config.build_settings['OTHER_LDFLAGS'] << ' -weak_framework'
        config.build_settings['OTHER_LDFLAGS'] << ' CoreMotion'
    end

    if  !config.build_settings['OTHER_LDFLAGS'].include? "-weak-lSystem"
        config.build_settings['OTHER_LDFLAGS'] << ' -weak-lSystem'
    end

    # Configs

    if config.name == 'Debug'
        
        if !config.build_settings['OTHER_CFLAGS'].include? "-fembed-bitcode-marker"
            config.build_settings['OTHER_CFLAGS'] << ' -fembed-bitcode-marker'
        end
        
    elsif config.name == 'Release' || config.name == 'ReleaseForProfiling' || config.name == 'ReleaseForRunning'
    
        if !config.build_settings['OTHER_CFLAGS'].include? "-fembed-bitcode"
            config.build_settings['OTHER_CFLAGS'] << ' -fembed-bitcode'
        end
    end
}

puts '-------- Build Pharses Names --------'
target.build_phases.each { |build_phase| 
    puts build_phase.isa
    if (build_phase.isa == 'PBXSourcesBuildPhase')
            build_phase.clear 
    end
}

puts '-------- Objects Names --------'
project.objects.each { |object| 
    puts object.display_name + ' TYPE: ' + object.isa
}

accepted_compile_sources_formats = [".cpp", ".mm", ".m"]
unaccepted_compile_sources_file_names = ['Unity_iPhone_Tests.m','RegisterMonoModules.cpp','main.mm']

accepted_header_formats = [".h"]
accepted_public_header_file_names = ["LifeCycleListener.h",'Preprocessor.h','RegisterFeatures.h','RenderPluginDelegate.h','UnityAppController.h','UnityForwardDecls.h','UnityInterface.h','UnityRendering.h','UnityViewControllerBase.h','UnityViewControllerBase+iOS.h']
unaccepted_header_file_names = ['RegisterMonoModules.h']

accepted_lib_formats = [".a"]

puts '-------- Add Files --------'
project.objects.each { |object| 

    if object.isa == 'PBXBuildFile'

        if object.file_ref.path != nil && File.extname(object.file_ref.path) != nil
            ext = File.extname(object.file_ref.path)
            fullname = File.basename(object.file_ref.path)

            if !unaccepted_compile_sources_file_names.include?(fullname) && accepted_compile_sources_formats.include?(ext)
                target.source_build_phase.add_file_reference(object.file_ref,true)
                puts 'ADDED TO COMIPLE SOURCES -> ' + object.file_ref.path
            end

            if !unaccepted_header_file_names.include?(fullname) && accepted_header_formats.include?(ext)
                is_public = false
                file = target.headers_build_phase.add_file_reference(object.file_ref,true)
                if accepted_public_header_file_names.include?(fullname)
                    file.settings = { 'ATTRIBUTES' => ['Public']}
                end
                puts 'ADDED TO HEADERS -> ' + object.file_ref.path + ' via PBXBuildFile PUBLIC -> ' + (is_public ? '1' : '0')
            end

        end

    elsif object.isa == 'PBXFileReference'

        if object.path != nil && File.extname(object.path) != nil
            ext = File.extname(object.path)
            fullname = File.basename(object.path)

            if !unaccepted_compile_sources_file_names.include?(fullname) && accepted_compile_sources_formats.include?(ext)
                target.source_build_phase.add_file_reference(object,true)
                puts 'ADDED TO COMIPLE SOURCES -> ' + object.path
            end

            if !unaccepted_header_file_names.include?(fullname) && accepted_header_formats.include?(ext)
                target.headers_build_phase.add_file_reference(object,true)
                puts 'ADDED TO HEADERS -> ' + object.path + ' via PBXFileReference'
            end

            if accepted_lib_formats.include?(ext)
                target.frameworks_build_phase.add_file_reference(object,true)
                puts 'ADDED TO FRAMEWORKS -> ' + object.path
            end
        end

    end
}

deleted_phases, preserved_phases = target.build_phases.partition{ |phase| phase.isa == 'PBXShellScriptBuildPhase' && phase.name == 'Replace Headers'}
target.build_phases.replace(preserved_phases)
uuid = Digest::MD5.hexdigest('Replace Headers').upcase[0,24]
run_script_phase = PBXShellScriptBuildPhase.new(project, uuid)
run_script_phase.initialize_defaults
run_script_phase.name = 'Replace Headers'
run_script_phase.shell_script = 'inputDirectory=$PROJECT_DIR/${TARGET_NAME}/FlatPathHeaders
outputDirectory=${BUILD_DIR}/${CONFIGURATION}-iphoneos/${TARGET_NAME}.framework/Headers

echo "in $inputDirectory"
echo "out $outputDirectory"

if [ ! -d "$outputDirectory" ]; then
echo "no out path,and create: $outputDirectory"
mkdir $outputDirectory
fi

cp -R $inputDirectory/. $outputDirectory/'
target.build_phases.insert(target.build_phases.length, run_script_phase)

# names = [ 'Foundation', 'CoreFoundation', 'MediaPlayer', 'CoreMotion', 'MediaToolBox', 'AudioToolbox', 'AVFoundation', 'CoreMedia', 'CoreLocation' ]
# names.each do |name|
#     target.add_system_framework(name)
# end

project.save

使用时将 Run Script 添加到导出的 Xcode 项目默认 target 中(其实这块也可以直接在 Unity 内通过 PBXProject 自动添加到 target 里去),然后直接 Run。项目并不会 Run 而是会 Cancel,因为 ruby 脚本在最后保存了工程。然后就会出现 UnityOutFramework,Build 即可。

2018.6.25

 • 

朋友圈里面不停有人发毕业典礼和离校,看得我总算是有点伤感的感觉了,然而我还有一堆学校的事情要处理,去检查了次课设试验被自以为是的老师气到不行,再一回想起之前被学校各种刁难,遂又回到了对毕业没有感觉的状态。

我真正关心的是由于课程和考试的安排在第一期毕业证发放之后,估计要拖到七月初我才能拿到毕业证了。我原本打算把 WWDC 之旅当做毕业旅行,这样即使我七月才能拿到毕业证也算是已经提前放松了一段时间,如此七月二十二立刻入职腾讯也不算什么对我而言太紧迫之事。但是 WWDC 由于签证被我错过,我一下子就感觉不爽了,这样刚毕业就去工作,让我想起了前一年在百度时不太好的感觉,而我本性难改,一旦觉得自己不自由就会不停折腾,直到我自己满意为止。

刚好上次 Hackathon 有一个推荐 MSRA 的机会,虽然应该是推不进去,但是给我了一个启发就是我还是能再往上争取一把的。因此我又动了心思想再看看机会,而且如果找到厉害的新东家还能九月份入职就更好了。我和同学说了这个事情,他们笑:你都拿腾讯当保底了。我说是,我现在是拿腾讯当保底了,但是一年前这个时候我可没这个胆量,这种事情自然是走一步看一步。

然后今天去寝室拿琐碎的东西,比如活动衫,原本是毕业典礼要穿的,结果我压根就没参加毕业典礼,因此一直放在班长那里;比如优秀论文证书,也是班长帮我拿的;比如一个厚册子,貌似是给同学之间写寄语和放照片用的,我拿到之后哭笑不得,这东西看起来情真意切但放到全是手机的现在怕是留着吃灰。

不管怎样,我的大学如果考过重修就应该还差一两周就结束了。
回想一下这四年,第一年还没什么具体的头绪,后面就一直在尽力地当一个了不起的盖茨比。
我爸妈没上过大学,对于现在的大学是什么样子什么做派也并不清楚,因此在我大学中和制度摩擦的时候也没有能力提供相应的指导,比如很多和学校硬碰硬的事情其实找个人就好办很多,但是我不知道,我爸妈也没有解决的思路,因此也是我慢慢上了四年才领悟到一些事情,如果早明白一些事情,也许我会保持自己在自己喜欢做的事情上的投入,同时在学校能够做出一个好学生的样子,甚至被当做学生学和做皆优的代表,少却很多麻烦,多了很多便利。因为没上过大学,我爸妈对我完成学业有一种执念,因此在我想要退学的时候反弹比较激烈,我也答应了至少要保证大学毕业,因此好歹和学校保持着联系,偶尔在学校露一次面,以完成这个保证。临近毕业和我爸妈说后面的发展,爸妈又说要考个研究生吧。我当然是有研究生的打算的,毕竟自己也没在这个学校里学到什么真的 CS 的东西,一个是学校没教,一个是教了也厌学,那自然有很多不会的内容,需要后面上学去补,而我的计划就是工作一两年,好歹逃离学校这种地方喘息一会,等到本科 GPA 对我的影响降低之后就去申请出国看看。虽然我研究生计划是这样的,但我和爸妈说的时候总会说不确定,因为我不想到时候再保证一次了,本来上学这种事情我都快有阴影了。
爸妈的这些反应我倒也明白,也没有觉得拖累,毕竟能定义拖累的前提是能够放下,而显然我之前也说过断绝关系这种事情我是做不来的,更何况虽然看起来最近半年全靠自己挣的钱过活没花过爸妈的,但是之前也说了这种看似买买买的自由的假象是建立在有爸妈的后备基础上的,目前简单的财务状况也不是能和真正成人前瞻后顾的财务计划能比的。因此我大学中也尽力缓和家人的关系,让家人理解我看似逃学一样的事情的动机,至少不再拦着我干活,然后我再想办法找时间去改变他们。
我越是想办法往上走越是想让我的父母理解我并且帮助我,特别是最近一次 WWDC 签证的事情之后,因为我和父母都觉得如果很早之前一家人一起办十年旅游签证就不会有我现在一个人被审查的事情了,而这种事情说实话是眼界的问题,但家长的态度和眼界这是个看运气的事情,自然会有家庭出身比我所在的境遇更糟糕,比如初中的那些同学们,而我也没什么可以抱怨的,即使最后爸妈不愿意改变,那也是他们自己的事情,但我至少要去尝试罢了。

大学最后一次课程设计检查

 • 

写了个项目去检查
我:老师我大四的,请问能不能这节课检查下,然后早点登记分数
老师:我是不可能给你一个人登记分数的,你要等大家都结束才行
我:那老师能不能先提前检查下,毕竟我也大四了
老师:不行,大四唯一的例外是有几个外语院的同学要回家了所以提前检查
我:但是昨天毕业典礼后大家都可以回家了,所以老师我也是想着能不能早点结束
老师:那你检查最多只能及格
我:好的好的
(老师翻点名册没找到我)
老师:你不是大四的吗,我这里只有一五级一六级的,你是怎么进来的?
(我同学帮我指了下我在花名册里面的位置)
老师看了下花名册里面的签到表:看你三次课里面两次都没来,你可以不用检查了(意指我可以挂科了)
我:老师我第一次和您在 QQ 上请假了,当时我和您说要去办签证参加 WWDC,第二次就是今天您刚才下午点名的时候我在改代码。
老师:行吧你给我看看你的东西
(看完我的项目)
老师:你刚才我只准备给你个及格,但是我听你讲了之后可以给你个中等
我:谢谢老师

大学其他对话系列:辅导员 | 软件外包赛校内答辩经过