项目地址 https://github.com/waylybaye/XcodeCleaner
其实这是一个RN的项目 , 并不是原生的
其实还挺好用的,很方便,节省了很多空间
技多不压身
把JS代码贴出来学习一下
/**
* Xcode Cleaner by waylybaye
* https://github.com/waylybaye/XcodeCleaner
* @flow
*/
import React, { Component } from 'react';
import {
AlertIOS,
AppRegistry,
Dimensions,
FlatList,
StyleSheet,
Text,
View,
TouchableOpacity,
ProgressViewIOS,
Button,
Image,
NativeModules,
ActivityIndicator,
LayoutAnimation,
} from 'react-native';
const {FileManager} = NativeModules;
function removePrefix(fullpath, path){
let endingSlash = path[path.length - 1] === '/';
return fullpath.substr(endingSlash ? path.length : path.length + 1);
}
function humanize(value, decimal) {
value = value || 0;
let i = -1;
let byteUnits = ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
do {
value = value / 1024;
i++;
} while (value > 1024);
return value.toFixed(decimal || 0) + byteUnits[i][0];
}
const STRINGS = {
'xcode_not_found_title': 'Xcode not found',
'xcode_not_found_body': "No Xcode installation found in selected directory, it's usually at HOME/Library/Developer."
};
export default class XcodeCleaner extends Component {
constructor(props){
super(props);
this.state = {
data: {},
progress: {},
tab: '',
};
}
componentWillMount(){
LayoutAnimation.easeInEaseOut();
}
async componentDidMount(){
this.calculateXcode();
}
updateProgress(section, current, total){
this.setState({
progress: {
...this.state.progress,
[section]: [current, total]
},
})
}
async calculateSubDirectory(path, progressKey, labelGetter) {
console.log('calculate Path', path);
let folders = [];
try{
folders = await FileManager.listDirectory(path, true);
} catch (e){
this.updateProgress(progressKey, 0, 0);
this.setState({
data: {
...this.state.data,
[progressKey]: {
size: 0,
groups: [],
}
}
});
return;
}
let totalSize = 0;
let groups = [];
this.updateProgress(progressKey, 0, folders.length);
for(let i=0; i console.log('Cancel Pressed'), style: 'cancel'},
{text: 'Choose Directory ...', onPress: () => this.calculateXcode(true)},
],
);
return;
}
await this.calculateSubDirectory(xcode + 'iOS DeviceSupport/', 'deviceSupport');
await this.calculateSubDirectory(xcode + 'DerivedData/', 'derivedData');
await this.calculateSubDirectory(xcode + 'Archives/', 'archives');
await this.calculateSubDirectory(authorizedPath + 'CoreSimulator/Devices/', 'simulator');
}
async componentWillUnmount(){
let home = await FileManager.getHomeDirectory();
let developer = `${home}/Library/Developer/`;
await FileManager.stopAuthorization(developer);
}
async trashDirectory(groupKey, item) {
let path = item.path;
if (path){
try{
await FileManager.trashDirectory(path);
let group = this.state.data[groupKey];
let index = group.groups.indexOf(item);
if (!group || index === -1){
return;
}
let groups = group.groups.slice();
groups.splice(index, 1)
this.setState({
data: {
...this.state.data,
[groupKey]: {
size: group.size - item.size,
groups: groups,
}
}
})
} catch (e){
console.log('errrr', e);
}
}
}
renderItem(item, groupKey){
return (
{item.label}
{humanize(item.size, 1)}
)
}
toggleTab(tab){
LayoutAnimation.easeInEaseOut();
this.setState({
tab: this.state.tab === tab ? null : tab,
});
}
render() {
let groups = [
{
name: 'iOS DeviceSupport',
key: 'deviceSupport',
description: 'Only need to keep the latest iOS version, feel free to remove old versions.',
},
{
name: 'DerivedData',
key: 'derivedData',
description: "It's safe to clear the entire folder, but you'll need to rebuild your projects after removal.",
},
{
key: 'archives',
name: 'Archives',
description: "You can't debug deployed versions if you remove old archives.",
},
{
key: 'simulator',
name: 'CoreSimulator',
description: "Your apps' data are stored here. I suggest you run `xcrun simctl delete unavailable` to reduce the size safely.",
}
];
return (
Cleaner for Xcode
{groups.map((group, idx) => {
let data = this.state.data[group.key] || {};
let progress = this.state.progress[group.key];
let progressValue = 0;
if (progress){
let current = progress[0];
let total = progress[1];
progressValue = total === 0 ? 1 : (current / total);
}
let count = data.groups ? data.groups.length : 0;
let compactMode = this.state.tab && this.state.tab !== group.key;
return (
this.toggleTab(group.key)}>
{group.name}
{count ? : null}
{!compactMode && {group.description} }
{data.size ? (
{humanize(data.size || 0)}
) : null}
{progress && progressValue < 1 ? : null }
{this.state.tab === group.key ? (
item.path}
renderItem={({item}) => this.renderItem(item, group.key)}
/>
) : null}
)
})}
);
}
}
const backgroundColor = 'transparent'
const cardBackground= 'transparent'
const textColor = '#333';
const secondaryTextColor = '#888';
const positive = 'blue';
// const fontFamily = 'HelveticaNeue';
const marginHorizontal = 20;
const sizeColor = 'rgb(255,78,93)';
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'space-between',
backgroundColor: backgroundColor,
paddingBottom: 20,
},
header: {
alignItems: 'center',
justifyContent: 'center',
paddingVertical: 10,
borderBottomWidth: 1,
marginHorizontal: marginHorizontal,
borderColor: sizeColor,
},
section: {
borderRadius: 10,
marginHorizontal: marginHorizontal,
paddingVertical: 20,
},
sectionHeader: {
},
row: {
flexDirection: 'row',
justifyContent: 'space-between',
},
rowLeft: {
flex: 1,
marginBottom: 10,
justifyContent: 'space-between',
},
rowRight: {
width: 100,
alignItems: 'flex-end',
},
name: {
fontSize: 18,
color: textColor,
// fontFamily: fontFamily,
fontWeight: 'bold',
},
description: {
fontSize: 12,
color: secondaryTextColor,
lineHeight: 20,
},
size: {
fontSize: 30,
color: positive,
fontWeight: 'bold',
color: sizeColor,
},
button: {
borderWidth: 1,
borderColor: '#fff',
},
buttonText: {
fontSize: 20,
color: positive,
},
title: {
fontSize: 15,
textAlign: 'center',
margin: 20,
fontWeight: 'bold',
// fontFamily: fontFamily,
color: '#888',
},
list: {
borderRadius: 8,
// borderWidth: 1,
// borderColor: '#444',
},
listContainer: {
backgroundColor: '#fff',
padding: 10,
},
listItem: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
},
itemLabel: {
color: secondaryTextColor,
flex: 1,
fontSize: 12,
},
itemSize: {
fontSize: 12,
marginRight: 10,
},
activeTab: {
flex: 1,
},
inactiveTab: {
height: 50,
},
compactSection: {
flexDirection: 'row',
justifyContent: 'space-between',
marginHorizontal: marginHorizontal,
borderWidth: 1,
alignItems: 'center',
},
headerWithBadge: {
flexDirection: 'row',
alignItems: 'center',
height: 20,
marginBottom: 10,
},
compactName: {
// color: secondaryTextColor,
// fontWeight: 'normal',
},
});
AppRegistry.registerComponent('XcodeCleaner', () => XcodeCleaner);