help tips

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash

help(){
cat << HELP
usage: dd ddk
example: 'wowo wowo'
HELP
exit 0
}

if [[ $1 == "" || $1 == "-h" ]]; then
echo 'what?'
help
fi

if [[ $1 != "" ]]; then
echo $1
fi

echo -e "\033]0;$1\007"

read from terminal

1
2
3
echo input your name:
read name
echo your name is ${name}

设置管理员密码

首次使用管理员登录需要先设置密码

1
sudo passwd

定时关机

http://os.51cto.com/art/201108/287974.htm

1
2
shutdown -h 22:30 # 在指定时间关机
shutdown -h 30 #30分钟后关机

history之后执行指定行的命令

$ history // 查看命令历史
$ !334 //表示执行第334行的命令

在命令行中用默认程序打开文件

xdg-open { file | URL }

Ubuntu下用命令行快速打开各类型文件(转)-bough22-ChinaUnix博客

ps 查看运行的进程

ps -aux | grep vim

Ubuntu 系统强制关闭进程。

$ps -aux | grep [应用名] # 抓取指定应用的进程信息,几下 应用的pid
$kill -9 [应用的pid]

cat

10行的上下文

1
cat file.txt | grep -C 10 key_word

tail

查看实时日志: tail -fn 100 log_file_name.out

1
2
3
tail --help
-f: `--follow[HOW]` Output appended data as the file grows;
-n: `--lines=[+]NUM` Output the last NUM lines, instead of the last 10;

sed

https://coolshell.cn/articles/9104.html

1
sed -i "s/'proxy.*/'proxy': 'http://proxy.lyloou.com'/g" eros.dev.js

nohup

用途:不挂断地运行命令。
语法:nohup Command [ Arg … ] [ & ]
描述:nohup 命令运行由 Command 参数和任何相关的 Arg 参数指定的命令,忽略所有挂断(SIGHUP)信号。在注销后使用 nohup 命令运行后台中的程序。要运行后台中的 nohup 命令,添加 & ( 表示”and”的符号)到命令的尾部。
http://www.cnblogs.com/allenblogs/archive/2011/05/19/2051136.html

nohup 不生成 nohup.out的方法

1
nohup java -jar /xxx/xxx/xxx.jar >/dev/null 2>&1 &

关键在于最后的 >/dev/null 2>&1 部分,/dev/null是一个虚拟的空设备(类似物理中的黑洞),任何输出信息被重定向到该设备后,将会石沉大海

/dev/null 表示将标准输出信息重定向到”黑洞”
2>&1 表示将标准错误重定向到标准输出(由于标准输出已经定向到“黑洞”了,即:标准输出此时也是”黑洞”,再将标准错误输出定向到标准输出,相当于错误输出也被定向至“黑洞”)
http://www.cnblogs.com/yjmyzz/p/4831182.html

在某目录及其子目录下所有文件的最前面添加几行文字

1
grep -rl '' tmpdir\ | xargs sed -i "1 i hi 你好吗\n 你知道我是谁吗\n 是的,是我\n"

lsof -i 8088

通过域名查看ip

  • ping的方式:ping lyloou.com
  • nslookup方式: nslookup lyloou.com

拉取远程文件

1
scp root@138.128.208.16:/root/go/src/github.com/inconshreveable/ngrok/bin/ngrok D:/dd/ngrok

如果出现这个错误:connect to xxxxxxx port 22: Connection refused

1
2
3
4
yum -y install openssh-server
service sshd start
# 首先使用命令:ss -lnt查询22号端口是否开启,如下图所示为正常开启,否则要开启22号端口。 如果要修改端口,查看或编辑SSH服务配置文件,使用命令 vi /etc/ssh/sshd.config,进入后把 port 后面默认的22端口改成别的端口即可.
# https://www.linuxidc.com/Linux/2017-11/148586.htm
1
2
3
# http://wiki.ubuntu.org.cn/UbuntuSkills#.E9.80.9A.E8.BF.87ssh.E4.BC.A0.E8.BE.93.E6.96.87.E4.BB.B6
scp -rp /path/filename username@remoteIP:/path #将本地文件拷贝到服务器上
scp -rp username@remoteIP:/path/filename /path #将远程文件从服务器下载到本地

df查看硬盘容量

1
df -h

how-to-automount-ntfs-partitions

  • vi /etc/fstab & add below line

    1
    2
    #Windows-Partition
    UUID=<xxxxx> /media/win ntfs rw,auto,users,exec,nls=utf8,umask=003,gid=46,uid=1000 0 0
  • Finding which disk you will set

    1
    sudo fdisk -l
  • Finding the UUID

    1
    sudo blkid
  • Check it

    1
    sudo mount -a

查看使用最多的10条命令

1
history | awk '{print $2}' | sort | uniq -c | sort -k1,1nr | head -10

https://coolshell.cn/articles/8619.html
http://blog.51cto.com/huanglianfeng/1381267

bash - How to use arguments from previous command? - Stack Overflow

1
2
3
4
5
6
7
8
9
10
11
$ echo a b c d e 
a b c d e
$ echo !^
echo a
a

$ echo a b c d e
a b c d e
$ echo !:1
echo a
a
1
2
3
4
5
6
7
8
9
10
11
12
!^      first argument
!$ last argument
!* all arguments
!:2 second argument

!:2-3 second to third arguments
!:2-$ second to last arguments
!:2* second to last arguments
!:2- second to next to last arguments

!:0 the command
!! repeat the previous line

kill

grep

查看包含部分文字的上下文

1
2
3
4
# -E, --extended-regexp     PATTERN is an extended regular expression
# -i, --ignore-case ignore case distinctions
-C, --context=NUM print NUM lines of output context
grep -E -i -C 10 "((exception) | (error))"

connection refused

https://askubuntu.com/questions/30080/how-to-solve-connection-refused-errors-in-ssh-connection

1
sudo apt-get install openssh-server openssh-client

将 ssh keys 复制到 user@host 以启用无密码 SSH 登录。

1
$ssh-copy-id user@host

将本地的文本文件保存到远程服务端中

1
2
cat ~/.ssh/id_rsa.pub | ssh user@123.45.56.78 "mkdir -p ~/.ssh && cat >>  ~/.ssh/authorized_keys"
https://www.digitalocean.com/community/tutorials/how-to-set-up-ssh-keys--2

bash - How can I ssh directly to a particular directory? - Stack Overflow

1
ssh -t xxx.xxx.xxx.xxx "cd /directory_wanted; bash"

How to enter ssh password using bash?

Create a new keypair: (go with the defaults)
ssh-keygen

Copy the public key to the server: (password for the last time)
ssh-copy-id user@my.server.com

From now on the server should recognize your key and not ask you for the password anymore:
ssh user@my.server.com

设置ngrok域名

ssh: connect to host localhost port 22: Connection refused

错误原因:
1.sshd 未安装
2.sshd 未启动
3.防火墙
解决方法:
1.确定安装sshd:
$ sudo apt-get install openssh-server
2.启动sshd:
$ sudo net start sshd
3.检查防火墙设置,关闭防火墙:
$ sudo ufw disable
检验方法,输入命令:
$ ssh localhost
若成功,则表示安装成功,且连接通过;
但是有的时候虽然成功了但是还是会出现Connection refused 问题。
运行 ps -e | grep ssh,查看是否有sshd进程:
有时候虽然可以看到sshd 但是还是不能连接成功
这时候就要想到重新启动一下:sudo service ssh restart

通过网页 Head 来获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private static String getWebsiteDatetime(String webUrl){
try {
URL url = new URL(webUrl);// 取得资源对象
URLConnection uc = url.openConnection();// 生成连接对象
uc.connect();// 发出连接
long ld = uc.getDate();// 读取网站日期时间
Date date = new Date(ld);// 转换为标准时间对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);// 输出北京时间
return sdf.format(date);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}

获取网页时间戳

(如果本地和网页时间相差不多,以后都以本地为主)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public static final String URL_CHECK_TIME = "http://www.taobao.com";
private static boolean useLocal;// 是否使用本地时间
private static long deltaTime; // 本机时间-网络时间;

public static void resetTimeStamp() {
useLocal = false;
deltaTime = 0;
}

/**
* 获取时间戳(首次从网上获取时间,和本地比较,如果相差在一定的范围内,以后的调用就直接使用本地的,如果相差很大,以后都以网页时间为准)
*
* @return 返回的是以秒为单位的时间字符串
*/
public static String getTimeStamp() {
final long phoneTime = System.currentTimeMillis() / 1000;

String result = String.valueOf(phoneTime);
if (!useLocal) {
// 之所以使用线程,是因为在Android中不允许在主线程中开启网络请求(NetworkOnMainThreadException)
new Thread(new Runnable() {
@Override
public void run() {
try {
URLConnection uc = new URL(URL_CHECK_TIME).openConnection();// 生成连接对象
uc.connect();// 发出连接
long webSiteTime = uc.getDate() / 1000;// 读取网站日期时间

// 获取到了网站时间,就进行比较
// 如果在范围内,下一次直接使用本地手机时间;
long currentTime = System.currentTimeMillis() / 1000;
useLocal = Math.abs(currentTime - webSiteTime) < 5 * 60;
deltaTime = currentTime - webSiteTime;

} catch (Exception e) {
Log.e(TAG, "getTimeStamp: ", e);
resetTimeStamp();
}

}
}).start();

result = String.valueOf(phoneTime - deltaTime);
}

Log.i(TAG, "getTimeStamp: 本次使用了本机时间?" + useLocal);
return result;
}

监听时间和日期变化

onCreate中添加注册

1
2
3
4
5
// 监听用户对时间和日期的修改;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_DATE_CHANGED);
registerReceiver(mReceiver, filter);

onDestroy中取消注册

1
unregisterReceiver(mReceiver);

mReceiver实现

1
2
3
4
5
6
7
8
9
10
11
12
13
BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()) {
// 时间发生变化后,重新设置时间戳
case Intent.ACTION_TIME_CHANGED:
case Intent.ACTION_DATE_CHANGED:
Log.i(TAG, "onReceive: Time or Date changed");
Utime.resetTimeStamp();
Utime.getTimeStamp();
}
}
};

直接获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class Utime {
private static final String URL_BASE = "https://sj.qq.com/";

/**
* 根据url这个网址来获取时间戳(如果获取此网络时间失败,使用本地时间)
* 返回的是以秒为单位的时间字符串
*
* @param url url
*/
public static String getTimeStamp(String url) {

final String urlRrBase = getBaseUrl(url);
final long currentTimeMillis = System.currentTimeMillis() / 1000;

try {
URLConnection uc = new URL(urlRrBase).openConnection();// 生成连接对象
uc.connect();// 发出连接
long webTimeMillis = uc.getDate();
long webTime = webTimeMillis / 1000;// 读取网站日期时间
return String.valueOf(webTime);
} catch (Exception e) {
return String.valueOf(currentTimeMillis);
}
}

private static String getBaseUrl(String url) {
if (TextUtils.isEmpty(url)) {
return URL_BASE;
}

try {
URI uri = new URI(url);
return uri.getScheme() + "://" + uri.getHost();
} catch (Exception e) {
return URL_BASE;
}

}
}

参考资料

为什么需要渠道打包

  • 为了统计各市场的效果(活跃数、下单数等),需要用某种方式唯一标识它们。
  • 客户端访问API时会在请求参数中带上渠道号,以便后台接下来计算不同渠道的效果。

添加渠道方法

AndroidManifest.xml中的application标签下添加:

1
2
3
4
<!-- UMENG配置 -->
<meta-data
android:name="UMENG_CHANNEL"
android:value="${UMENG_CHANNEL_VALUE}"/>

build.gradle文件中的android标签下添加:

1
2
3
4
5
6
7
8
9
10
11
productFlavors {
xiaomi {}
qihu360 {}
baidu {}
wandoujia {}
// ...
}

productFlavors.all {
flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}

获取渠道方法

在java代码中获取:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 调用方式
Utoast.show(this, "渠道:" + getApplicationMetaValue(this, "UMENG_CHANNEL"));

public static String getApplicationMetaValue(Context context, String name) {
String value = "";
try {
ApplicationInfo appInfo = context.getPackageManager()
.getApplicationInfo(context.getPackageName(),
PackageManager.GET_META_DATA);
value = appInfo.metaData.getString(name);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return value;
}

扩展(更快速的打包方式):

渠道打包的另一种解决方案:使用python脚本在META-INFO中添加channel_<渠道名>名称的空文件;

友盟提供的设置渠道方案

  1. 就是上面的通过AndroidManifest配置

    1
    <meta-data android:name="UMENG_CHANNEL" android:value="UMeng" />
  2. 通过在代码中执行

    1
    2
    String channel = getApplicationMetaValue(this, "UMENG_CHANNEL");
    AnalyticsConfig.setChannel(channel);

NOTE1: 坑,不能同时设置两种方式,友盟技术的解释是优先使用第一次取到了渠道名;如果采用java代码的方式,需要在Application中设置,而不是Activity

NOTE2: 也可以通过url将渠道名传递给后台,由后台来做统计;

参考资料

从keystore中获取md5

1
keytool.exe -v -list -keystore lyloou.jks

通过本地安装的支付宝支付

Android端的实现比较简单,

  1. 下载SDK和DEMO
  2. 导入支付宝sdk后,需要注意权限、配置、混淆等;
  3. 通过后台获取得到orderInfo字符串
  4. 唤起支付宝:【需要在新线程中调用支付接口。(可参考alipay_demo实现)】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
final String orderInfo = "从后台获取得到的orderInfo";

PayTask alipay = new PayTask(mActivity);
Map<String, String> result = alipay.payV2(orderInfo, true);
PayResult payResult = new PayResult(result);
/**
对于支付结果,请商户依赖服务端的异步通知结果。同步通知结果,仅作为支付结束的通知。
*/
String resultInfo = payResult.getResult();// 同步返回需要验证的信息
String resultStatus = payResult.getResultStatus();

// 判断resultStatus 为9000则代表支付成功
if (TextUtils.equals(resultStatus, "9000")) {
// 该笔订单是否真实支付成功,需要依赖服务端的异步通知。
Toast.makeText(mActivity, "支付成功", Toast.LENGTH_SHORT).show();
} else {
// 该笔订单真实的支付结果,需要依赖服务端的异步通知。
Toast.makeText(mActivity, "支付失败", Toast.LENGTH_SHORT).show();
}

如果本地没有安装支付宝,就跳转到wap支付

我相信在PayTask.payV2中,有对是否安装支付宝做判断,
我们需要在Manifest中注册H5PayActivity

1
2
3
4
5
6
7
<activity
android:name="com.alipay.sdk.app.H5PayActivity"
android:configChanges="orientation|keyboardHidden|navigation"
android:exported="false"
android:screenOrientation="behind"
android:windowSoftInputMode="adjustResize|stateHidden" >
</activity>

参考资料

免费

  • 信鸽

第三方推送服务

  • 友盟
  • 极光推送

手机ROM厂商推送

Flyme

Flyme推送目前支持哪些平台?
Flyme推送平台目前只支持魅族手机的flyme系统。

Android推送中,多个app都使用推送时,他们会共享连接吗?
在Flyme系统(4.0,4.5,5)上,会直接使用系统长连接通道,所有app会和系统共享一个长连接;目前在其他Rom上,没有共享连接。

Flyme推送收费吗?
Flyme推送平台的基础推送功能是免费的,但是某些定制功能会考虑收费,在功能和体验上会有不同。

参考资料
http://open-wiki.flyme.cn/index.php?title=魅族推送平台常见问题

MIUI

小米消息推送服务在MIUI上为系统级通道,并且全
平台通用,可以为开发者提供稳定、可靠、高效的
推送服务

参考资料

华为

参考资料

渠道列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
10086com
189store
360mobile
3gcn
91market
anzhi
appchina
baidu
gfan
googleplay
hicloud
lenovomm
meizu
mumayi
myapp
nduoa
samsungapps
uc
wandoujia
wostore
xiaomi
yingyongbao
yingyonghui

bulid.gradle 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  signingConfigs {
renrenDebug {
keyAlias 'test'
keyPassword 'test'
storeFile file('../tool/test.key')
storePassword 'test'
}
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
jniLibs.srcDirs = ['libs']
}
}

lintOptions {
abortOnError false;
}
buildTypes {
debug {
signingConfig signingConfigs.debug
shrinkResources false
zipAlignEnabled false
minifyEnabled false

// 测试
buildConfigField "boolean", "TEST_ENV", "true"
manifestPlaceholders = [WECHATAPPID: "wxea2b67dxxxxxx"]
}

release {
signingConfig signingConfigs.release // 密钥配置
shrinkResources true // 删除不必要的源文件
zipAlignEnabled true // 压缩对齐
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

// 正式
buildConfigField "boolean", "TEST_ENV", "false"
manifestPlaceholders = [WECHATAPPID: "wxb093774eaxxxxxx"]

applicationVariants.all { variant ->
variant.outputs.each { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.apk')) {
// 输出apk名称为 LOU_20161101_V0.2.0.apk
def fileName = "LOU_${releaseTime()}_V${defaultConfig.versionName}.apk"
output.outputFile = new File(outputFile.parent, fileName)
}

}

}
}
}

// AndroidManifest的application标签下添加: <meta-data android:name="UMENG_CHANNEL" android:value="${UMENG_CHANNEL_VALUE}" />

// productFlavors {
// yingyongbao {}
// wandoujia {}
// xiaomi {}
// qihu360 {}
// baidu {}
// meizu {}
// }
//
// productFlavors.all {
// flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
// }
}

def releaseTime() {
return new Date().format("yyyMMdd", TimeZone.getTimeZone("UTC"))
}

proguard 混淆配置

为什么要过滤混淆

http://blog.csdn.net/fengyuzhengfan/article/details/43876197)
ProGuard 默认会对第三方库也进行混淆的,而第三方库有的已经混淆过了,有的使用了 Java 反射技术,所以我们在进行代码混淆的时候要排除这些第三方库。排除对第三方库的混淆需要在混淆规则文件(通常是:proguard-project.txt 或 proguard.cfg 或 proguard-rules.pro 或 proguard-rules.txt 也可以是其它的文件名只要在配置文件中将含有混淆规则的文件名配置进去就行了)中添加如下规则: 1.如果使用了 Gson 之类的工具要使 JavaBean 类即实体类不被混淆。 2.如果使用了自定义控件那么要保证它们不参与混淆。 3.如果使用了枚举要保证枚举不被混淆。 4.对第三方库中的类不进行混淆

proguard-rules.pro 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
-keepclassmembers class fqcn.of.javascript.interface.for.webview {
public *;
}

# 忽略警告
-ignorewarning

# 移除日志
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** i(...);
public static *** w(...);
}


参考资料

Avoid Maven dynamic dependency resolution. (such as 2.1.+)

this result in different and unstable builds or subtle, untracked difference
in behavior between builds.

在配置 build.gradle 的时候,避免直接写入敏感信息(例如:密码),而是写入到版本控制工具

忽略的文件gradle.properties中。

https://github.com/futurice/android-best-practices#gradle-configuration

针对测试版本和发布版本使用不同的 appId, 这样两个版本就可以同时存在在一个设备上了。

可以通过前缀或后缀的方式来区分。

https://github.com/futurice/android-best-practices#gradle-configuration

使用 Maven 依赖方案代替使用导入 jar 包方案

如果在你的项目中你明确使用率 jar 文件,那么它们可能成为永久的版本,如 2.1.1.下载 jar 包更新他们是很繁琐的, 这个问题 Maven 很好的解决了,这在 Android Gradle 构建中也是推荐的方法。你可以指定版本的一个范围,如 2.1.+,然后 Maven 会自动升级到制定的最新版本,例如:

1
2
3
4
5
6
7
8
9
dependencies {
compile 'com.netflix.rxjava:rxjava-core:0.19.+'
compile 'com.netflix.rxjava:rxjava-android:0.19.+'
compile 'com.fasterxml.jackson.core:jackson-databind:2.4.+'
compile 'com.fasterxml.jackson.core:jackson-core:2.4.+'
compile 'com.fasterxml.jackson.core:jackson-annotations:2.4.+'
compile 'com.squareup.okhttp:okhttp:2.0.+'
compile 'com.squareup.okhttp:okhttp-urlconnection:2.0.+'
}

参考资料

0%